eInvoice Viewer for PEPPOL & EN16931

Description

Try the live demo – upload an XRechnung, ZUGFeRD/Factur-X or Peppol BIS invoice and see it rendered instantly.

eInvoice Viewer for PEPPOL & EN16931 turns an uploaded electronic invoice into a clear, structured HTML view directly on your page – without any external service and without storing the file.

Add the [einvoice_viewer] shortcode to a page and your visitors can drag and drop an electronic invoice into the viewer. The document is read and rendered entirely in the visitor’s own browser – it is never uploaded to your server. The result (invoice header, parties, order and delivery data, payment details, line items, VAT breakdown and totals) appears instantly, without a page reload and without a single byte of the invoice ever crossing the network. The layout is inspired by the official ZUGFeRD Quba viewer and is rendered inside a Shadow DOM, so it looks identical in every theme.

Supported formats

  • ZUGFeRD / Factur-X (PDF) – the embedded XML is extracted and read automatically.
  • CII (UN/CEFACT) XML – read directly.
  • UBL / XRechnung (XML) – converted to CII internally and then read.

Highlights

  • Drag & drop uploader – vanilla JavaScript, no framework, no page reload.
  • Complete field coverage – all 164 EN 16931 business terms and all 32 business groups, verified against 125 official sample invoices. Empty fields are shown as placeholders on purpose, so you can see which terms the standard defines and which ones this invoice omitted.
  • Business-term labels with a short description – each field can carry its BT / BG code, and hovering it shows the term name plus a short description of the field in German, English or French. Further details (cardinality, data type, business rules) are provided by the separate “eInvoice Viewer – Technical Details” extension. Toggled live, per setting or via the shortcode attribute bt="1" / bt="0".
  • Trilingual – the interface is available in English, German and French.
  • Theme-independent – rendered inside a Shadow DOM with a full style reset, so no theme styles leak through.
  • The document never leaves your browser – reading and rendering both happen client-side; your server never receives the file, so there is nothing to store, log or leak in the first place.
  • Secure by design – the invoice is parsed by the browser’s own DOMParser (no server-side XML parser, so no XXE surface for the upload itself); every invoice value is escaped on output. Sibling paid extensions that genuinely need server-side processing (validation, export, …) keep their own independent upload, nonce and rate-limit handling.
  • Extensible – additional layouts can be added as a template subclass, and a structured-data API returns the whole invoice as a nested array. Two filters (spev_code_tooltip, spev_invoice_model) let an add-on extend the BT/BG tooltips and the invoice model itself.

Third-party libraries

Since reading moved into the browser, the only bundled third-party code is Mozilla pdf.js (assets/js/pdfjs/, Apache License 2.0, license text next to the files), used to pull the embedded XML out of a ZUGFeRD / Factur-X PDF. Everything else in vendor/ is this plugin family’s own code under GPL-2.0-or-later; composer.lock lists it.

Demo

Try the viewer without installing anything: live demo on invoicePress.de. Drop in your own e-invoice; it is read and rendered in your browser, exactly as on your own site. The plugin itself never contacts the demo site.

Screenshots

Installation

  1. Upload the plugin folder to /wp-content/plugins/ or install it through the WordPress plugins screen.
  2. Activate the plugin through the “Plugins” screen in WordPress.
  3. Add the shortcode [einvoice_viewer] to any page or post. To show the EN 16931 business-term numbers initially, use [einvoice_viewer bt="1"].
  4. Optionally adjust the options under Settings -> E-Invoice Viewer (daily upload limit, maximum file size, proxy header, default BT visibility, layout template).

FAQ

Is the uploaded invoice stored anywhere?

No. The invoice is read and rendered entirely in the visitor’s own browser – it is never sent to your server, so there is nothing to store, log or delete. Nothing is written to the uploads directory or the database. (Paid sibling extensions that genuinely need server-side processing, such as validation or export, do their own upload and say so.)

Which invoice formats are supported?

ZUGFeRD and Factur-X PDFs (the embedded XML is extracted), plus CII (UN/CEFACT) XML and UBL / XRechnung XML.

Why does the view not look pixel-perfect like the Quba viewer?

The Quba viewer transforms the invoice with the KoSIT XRechnung XSLT 3.0 via Saxon-JS. PHP only supports XSLT 1.0, so an own, Quba-inspired PHP template is used instead – functionally equivalent, but not the identical KoSIT markup.

Can I limit how many invoices a visitor can upload?

Yes. Under Settings -> E-Invoice Viewer you can set a daily upload limit per visitor (logged-in users are counted by user ID, anonymous visitors by hashed IP address).

Reviews

There are no reviews for this plugin.

Contributors & Developers

“eInvoice Viewer for PEPPOL & EN16931” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

2.14.10

  • Changed: the bundled business-term catalogue is now much smaller (about 1.0 MB down to 0.2 MB) because it only carries what the viewer actually shows. The tooltips are unchanged: term name and a short description in German, English or French.
  • Fixed: the FAQ still said the invoice was uploaded to your server and that browser-side reading would come “in a future version” – it has been client-side since 2.12.0. The answer now describes what the plugin actually does.
  • Changed: removed an unused internal file left over from the move to client-side rendering.

2.14.9

  • Fixed: the “eInvoice Viewer — Technical Details” add-on’s tooltip enrichment (cardinality, data
    type, applicable rules, XSD level, reference table, CII/UBL path) stopped appearing when this
    plugin’s own rendering moved fully client-side – its PHP filter hook no longer fires for that
    code path. The BT/BG tooltip now calls that add-on’s own client-side module directly, the same
    way the Extended Profiles add-on’s model extension was already fixed.

2.14.8

  • Fixed: when a trade party (seller, buyer, delivery location, payee) carries both a plain
    identifier and a global identifier (e.g. an ERP customer number alongside a GLN) at the same
    time, the plain identifier was silently dropped and its value shown mislabeled under the
    global-identifier’s BT tag. Both are now shown independently under their own correct BT tags
    (BT-29/-46/-60/-71 for the plain identifier, the matching “-0″/”-1″ tags for the global
    identifier and its scheme).

2.14.7

  • Fixed: on some hosts, uploading a PDF failed with “Failed to fetch dynamically imported module” –
    the bundled pdf.js files used the newer .mjs extension, which some servers have no correct file
    type mapping for. Renamed to the universally-supported .js extension; no behaviour change.

2.14.6

  • Fixed: the pdf.js library the PDF-reading fix in 2.14.5 relies on was loaded from a third-party
    CDN (cdnjs.cloudflare.com) – it is now bundled with the plugin instead, same as every other
    script and font here.

2.14.5

  • Fixed: uploading a PDF (ZUGFeRD/Factur-X) still failed with “The PDF does not contain a readable
    e-invoice” even after 2.14.3’s pdf.js fix – a pdf.js update changed how attached files are read,
    and this plugin’s own code had not caught up. Verified this time against multiple real ZUGFeRD/
    Factur-X sample invoices before release, not just claimed fixed.

2.14.4

  • Changed: the visitor-facing colour accent (previously teal-blue and orange, from the original
    product logo) is now the same navy used across the rest of the specialPress/invoicePress tool
    family, so the plugin’s look matches the family it belongs to.

2.14.3

  • Fixed: uploading a PDF (ZUGFeRD/Factur-X) failed with “PDF reading needs pdf.js, which this page
    has not loaded.” – the PDF-reading library is now loaded automatically, only when a PDF is
    actually uploaded.
  • Fixed: for a UBL/PEPPOL-BIS invoice, several fields (party identifier schemes, unit codes, the
    payment means name, item classification codes) always rendered empty regardless of the document’s
    actual content.
  • Fixed: for a UBL/PEPPOL-BIS invoice, the delivery information section (deliver-to party, address,
    delivery date) always rendered empty regardless of the document’s actual content.

2.14.2

  • Fixed: on some sites the upload widget could render an empty box with no error – depended on the
    active theme’s own template structure, not anything a visitor did. The required script could end
    up queued before it was registered, which silently dropped the configuration data it needed.

2.14.1

  • Fixed: the plugin header was missing a “Requires PHP” line.

Note: versions 2.12.5 through 2.14.0 are not documented here yet – this file’s changelog fell behind
the plugin’s actual version for a stretch and has not been fully backfilled.

2.12.4

  • Fixed: the paid “Extended Profiles” add-on’s fields (Ship From, Invoicer, Invoicee, Product end user, Ultimate ship to, Buyer tax representative, document flags, cash discount / penalty payment terms, further references) had silently stopped appearing in the rendered invoice since 2.12.0, because the add-on’s own server-side hook no longer fires now that rendering happens entirely in the browser. It now hooks into the same client-side render path directly.

2.12.3

  • The “Export to Excel” and “Visualizer” add-on buttons now also read the already-built client-side identifier model instead of re-sending the file for a second server-side parse – completes the same move for all four toolbar bridge extensions (Inbound Check and Identifier Check already made it in 2.12.1/2.12.2).

2.12.2

  • The Identifier Check add-on now also reads the already-built client-side identifier list instead of re-sending the file for a second server-side parse – the same move already made for the Inbound Check add-on in 2.12.1. The remaining extensions (Excel export, Visualizer, Technical Details) still parse server-side for now and are unaffected either way.

2.12.1

  • The already-built client-side model is now also handed to any extension that asks for it, instead of the extension re-sending the file for a second server-side parse. The Inbound Check add-on is the first to use this (its findings are now unaffected by this plugin’s own move to client-side rendering); the remaining extensions still parse server-side for now and are unaffected either way.

2.12.0

  • The invoice is now read and rendered entirely in the browser – it is never uploaded to the server. The upload endpoint, its nonce and its daily rate limit are gone from this plugin; the shortcode’s own JavaScript parses and renders the file client-side, using the same code the standalone @einvoice/core Web Component uses. The paid companion extensions (KoSIT validator, Excel export, Visualizer, Identifier Check, Inbound Check, Technical Details) are unaffected and keep working exactly as before – they each still send the file to their own, independent endpoint when their own feature is used.
  • Business-term tooltips are now fetched and rendered client-side too, in the visitor’s own language (German/English/French, same as before).
  • Known, temporary trade-off: the Technical Details add-on’s tooltip extension (cardinality, data type, applicable rules) is not yet available in the client-rendered view – the BT/BG tooltip still shows the term name and description, just without that extra detail for now.

2.10.10

  • The upload dialog now measures exactly the same width (900px) in the Viewer, the Validator and the Explainer, matching the two existing tools instead of the other way round.

2.10.9

  • Fixed: the rendered invoice was capped to the upload box’s own, narrower width instead of using the full width available to the shortcode.

2.10.8

  • New “Field Browser” and “Rule Browser” buttons in the result toolbar when the companion eInvoice Viewer – Technical Details add-on is active – each opens pre-filtered to the uploaded invoice’s own syntax (CII/UBL), scope (EN16931/EXTENDED) and rule set.

2.10.7

  • New spev_register_settings action lets a companion add-on (currently the Exporter) add its own settings block to this plugin’s own Settings page.

2.10.4

  • The shared rate-limiting/nonce/REST plumbing is now vendored via Composer instead of a hand-copied folder – internal packaging change, no user-visible effect.

2.10.3

  • Updated the bundled horstoeko/invoicesuite library to v0.0.31, which fixes an upstream bug where the buyer’s contact card could show the seller’s contact name, phone and e-mail instead of the buyer’s own.

2.10.2

  • The document hero no longer shows BT badges, even with “Show BT numbers” on – the same fields already carry their BT code in the Invoice data card below.
  • Swapped the display position of BT-5 (Currency) and BT-74 (End date) in the Invoice data card.
  • In the allowances/charges and VAT breakdown tables, each cell’s BT/BG badge now renders above its value instead of beside it.
  • The “Allowances & charges” table heading now names both business groups it covers (BG-20 and BG-21).

2.10.1

  • Fixed: the buyer’s contact card silently showed the seller’s contact name, phone and e-mail (BT-56/BT-57/BT-58) whenever a document had a seller contact but no buyer one – worked around a bug in the vendored horstoeko/invoicesuite library.
  • Fixed: BT-10 (Buyer reference) was shown twice – once correctly under Invoice data, a second time under Buyer information where it does not belong.
  • Fixed: BT-33 (Seller further legal information) never displayed even when the source document carried it.

2.10.0

  • New SPEV_Renderer::model_json() – the same model as model(), as a JSON string. Purely additive; model() itself is unchanged.
  • New spev_register_templates action: a companion plugin can register additional layouts from the outside without touching this plugin’s code. First consumer: the new eInvoice Viewer – Visualizer add-on, four print-oriented layouts selectable in Settings -> E-Invoice Viewer -> Layout template.

2.9.0

  • Rate limiting and the einvoice/v1 REST namespace unified with the companion Explainer, Validator and Exporter plugins into a shared library – existing settings carry over unchanged. New route POST /wp-json/einvoice/v1/render, alongside the existing admin-ajax.php action.
  • horstoeko/invoicesuite updated to v0.0.30.

2.8.0

  • Optional Excel export button in the result view when the companion eInvoice Viewer – Exporter add-on is active.

2.7.0

  • Optional “Check with KoSIT” button in the result view when the companion eInvoice Validator add-on is active – runs the official KoSIT Validator against the uploaded invoice and shows the report in the Validation Explainer’s own layout, without leaving the page.

2.6.1

  • Two more coded fields resolved to their designation instead of showing a bare code: BT-21 (note subject code) and BT-128-0 (scheme of a line’s object identifier).

2.6.0

  • Fixed: the uploader dialog and its status messages always showed the site’s default language instead of the current visitor’s own language, even though the rendered invoice already respected it correctly (a WordPress quirk: requests through admin-ajax.php resolve the locale differently from an ordinary page load).
  • Code values are now shown as “code – designation” throughout (was “designation (code)”).
  • More coded fields resolved to their designation instead of a bare code: BT-29-1 / BT-46-1 (scheme of the seller/buyer identifier), BT-30-1 / BT-47-1 (scheme of the registration number), BT-34-1 / BT-49-1 (scheme of the electronic address) and BT-157-1 (scheme of the item identifier).
  • Fixed: a long CII/UBL XPath in a business-term tooltip could overflow the tooltip box instead of wrapping onto a new line.

2.5.3

  • The reading engine now uses horstoeko/invoicesuite instead of horstoeko/zugferd (no visible change for existing installations).

2.5.2

  • Fixed: BT-29-1 / BT-46-1 (scheme of the seller/buyer identifier) stayed empty when the source invoice carried the scheme on the plain identifier element instead of the separate global-identifier element – a real-world pattern the reading library’s own convenience API does not expose on its own.

2.5.0

  • New spev_invoice_model filter lets an add-on append whole additional sections to the invoice model.

2.4.0

  • New spev_code_tooltip filter lets an add-on extend a business-term tooltip with additional information (cardinality, data type, reference table, XSD level, XPath).
  • Fixed: the business-term tooltip cache was shared across every rendered invoice instead of being scoped to one render, which could show one invoice’s tooltip wording on another.

2.3.0

  • Typography and colour palette aligned with the companion Validation Explainer plugin (Inter / Space Grotesk / JetBrains Mono, a neutral grey scale); the brand colours themselves are unchanged.

2.2.0

  • Consistent section headers: a business group that opens its own block now always carries the same header tab, and a group nested inside another block (for example the tax representative’s postal address, BG-12 inside BG-11) is marked with its own, fainter tab. The dark / light distinction keeps its meaning, dark for a block that carries data and light for an empty one.
  • Dates and numbers now follow the site instead of being hard-coded German. Invoice dates use the format from Settings -> General (new spev_date_format filter), numbers and amounts use the separators the active locale declares. On an English installation the invoice date read 13.11.2017 and the total 6.125,00 EUR before this release. Calendar dates are formatted in their own time zone on purpose, so the day printed is always the day that stands in the XML.
  • Fixed: the document type, payment means, unit of measure, VAT category and country were shown in German whatever the interface language. All five are translatable now, with the code appended in brackets, for example “Credit note (381)” or “kg (KGM)”; the section header keeps the plain name. Included in this: an unknown document type code was reported as “invoice”, so a credit note carrying a code the plugin did not know was labelled an invoice – a false statement about a legal document. An unknown code is now shown as the code itself, and a missing one is left empty.
  • Documented the license of every bundled dependency: extracting the XML from a ZUGFeRD / Factur-X PDF uses smalot/pdfparser under the LGPL-3.0, everything else is MIT and the plugin’s own reading engine is GPL-2.0-or-later.
  • Tested against WordPress 7.1.

2.1.0

  • Complete EN 16931 coverage: all 164 business terms and all 32 business groups are now extracted and labelled (previously 119 and 9). The seller tax representative (BG-11/BG-12) and payee (BG-10) blocks were not read at all before.
  • Business-term tooltips in German, English and French, taken verbatim from the official Factur-X specification.
  • French interface translation added; the German one extended to cover the new strings.
  • Fixed: the allowances and charges table was labelled BG-20 throughout, which was wrong for every charge row. The business-term code is now decided per row (BG-20 vs BG-21, and BG-27 vs BG-28 on line level).
  • Fixed: on Windows servers every upload failed with “No file received.” because the temporary upload path was passed through wp_unslash(), which strips its backslashes.
  • Values that were read but discarded are now displayed: allowance and charge base amounts, percentages and reason codes, the item attribute value (BT-161) and the line identifier (BT-126).
  • The reading engine was extracted into a CMS-neutral library; the plugin’s own renderer shrank from about 1,100 lines to a thin bridge.
  • Bundled dependencies reduced from 126 MB to 17 MB by dropping an unused PDF-writing chain the plugin never referenced.
  • New: SPEV_Renderer::model() returns the structured invoice data instead of HTML.
  • New: the spev_label_locale filter chooses the business-term language independently of the site language.

2.0.1

  • Business-term corrections, verified against the official EN 16931 specification (BT-115, BT-28/BT-33, BT-56/BT-41, BT-10, BT-47/BT-30 and the added scheme fields BT-47-1 / BT-30-1).
  • Updated and recompiled translations.
  • Renamed the plugin to “invoicePress – e-Invoice Viewer”.
  • Switched the text domain to sp-einvoice-viewer and hardened input handling (uploads and proxy headers) for the WordPress coding standards.

2.0.0

  • New rectangular Quba-style layout with coloured section tabs and a dedicated card group per line item.
  • Introduced the template engine (data model separated from HTML rendering).
  • Many more fields (BT-127 to BT-160, payment cards, delivery details and more).