npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tomaszatoo/wp-shortcode

v0.0.2

Published

Angular library for rendering WordPress shortcodes as native Angular components

Readme

@tomaszatoo/wp-shortcode

Angular library for rendering WordPress shortcodes as native Angular components.

When you load WordPress post or page content via the REST API, shortcode tokens like [gallery id="123"] arrive as raw strings inside the HTML. This library parses those tokens and replaces them with real Angular components — with full change detection, dependency injection, and reactive @Input() binding.

For architecture details and workspace setup see the workspace README.


Installation

npm install @tomaszatoo/wp-shortcode

Requires Angular 17+.


Quick start

1. Create a shortcode component

Any standalone Angular component works. It receives the shortcode attributes and (for enclosing shortcodes) the inner HTML via standard @Input():

// gallery.component.ts
import { Component, Input, OnInit } from '@angular/core';

@Component({
  selector: 'app-gallery',
  template: `
    <div class="gallery" [attr.data-id]="attrs['id']" [attr.data-size]="attrs['size']">
      <!-- your gallery implementation -->
    </div>
  `,
})
export class GalleryComponent {
  @Input() attrs: Record<string, string> = {};  // { id: '123', size: 'medium' }
  @Input() inner = '';                           // inner HTML (enclosing shortcodes only)
}

2. Register shortcodes in your app config

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideShortcodes } from '@tomaszatoo/wp-shortcode';
import { GalleryComponent } from './gallery.component';
import { CaptionComponent } from './caption.component';

export const appConfig: ApplicationConfig = {
  providers: [
    provideShortcodes([
      { tag: 'gallery', component: GalleryComponent },
      { tag: 'caption', component: CaptionComponent },
    ]),
  ],
};

3. Render shortcodes in a template

// post.component.ts
import { Component } from '@angular/core';
import { WpShortcodeComponent } from '@tomaszatoo/wp-shortcode';

@Component({
  selector: 'app-post',
  imports: [WpShortcodeComponent],
  template: `<wp-shortcode [content]="post.content.rendered" />`,
})
export class PostComponent {
  post = /* ... loaded from WP REST API */;
}

That's it. Any [gallery], [caption], or other registered shortcode inside post.content.rendered is replaced by the corresponding Angular component.


Shortcode syntax support

| Format | Example | Supported | |---|---|---| | Self-closing | [gallery id="1" size="medium"] | ✅ | | Self-closing with slash | [nextpage /] | ✅ | | Enclosing | [caption align="left"]text[/caption] | ✅ | | Nested (via inner recursion) | [outer][inner /][/outer] | ✅ | | Escaped | [[gallery]] | ✅ (left as-is) |

Attribute formats

[tag name="double quoted"]
[tag name='single quoted']
[tag name=unquoted]
[tag "positional"]          ← stored as key "0", "1", …

Enclosing shortcodes

When WordPress uses [tag]content[/tag] syntax, the inner HTML is passed to your component's inner input as a raw string. Your component decides what to do with it:

// caption.component.ts
import { Component, Input } from '@angular/core';
import { WpShortcodeComponent } from '@tomaszatoo/wp-shortcode';

@Component({
  selector: 'app-caption',
  imports: [WpShortcodeComponent],
  template: `
    <figure [class]="attrs['align']">
      <!-- recursively process shortcodes inside the caption -->
      <wp-shortcode [content]="inner" />
      <figcaption>{{ attrs['caption'] }}</figcaption>
    </figure>
  `,
})
export class CaptionComponent {
  @Input() attrs: Record<string, string> = {};
  @Input() inner = '';
}

Using <wp-shortcode [content]="inner"> inside your component enables recursive/nested shortcode processing.


Lazy-loaded feature modules

provideShortcodes() uses Angular's multi provider — you can call it as many times as needed, including inside lazy routes:

// feature.routes.ts
export const routes: Routes = [
  {
    path: 'shop',
    providers: [
      provideShortcodes([
        { tag: 'product', component: ProductComponent },
        { tag: 'add-to-cart', component: AddToCartComponent },
      ]),
    ],
    loadComponent: () => import('./shop/shop.component'),
  },
];

Programmatic registration

Use ShortcodeRegistry directly when you need to register components at runtime (e.g. after a dynamic import):

import { inject } from '@angular/core';
import { ShortcodeRegistry } from '@tomaszatoo/wp-shortcode';

const registry = inject(ShortcodeRegistry);
registry.register('my-tag', MyComponent);

Parser utilities

The parser is exported as a standalone pure function — useful for pre-processing, server-side rendering, or building your own renderer:

import { parseShortcodes, parseAttributes } from '@tomaszatoo/wp-shortcode';

const segments = parseShortcodes('<p>Hello</p>[gallery id="1"]<p>World</p>');
// [
//   { type: 'html',      html: '<p>Hello</p>' },
//   { type: 'shortcode', tag: 'gallery', attrs: { id: '1' }, inner: '' },
//   { type: 'html',      html: '<p>World</p>' },
// ]

const attrs = parseAttributes('id="1" size="medium"');
// { id: '1', size: 'medium' }

Security note

HTML segments between shortcodes are rendered via Angular's DomSanitizer.bypassSecurityTrustHtml(). This is intentional — WordPress content regularly contains iframes (YouTube, Vimeo), plugin-injected scripts, and custom attributes that Angular's default sanitizer would strip.

Only pass content from sources you control (your own WordPress instance). Never pass user-submitted or third-party HTML directly.


Layout note

Each HTML segment is wrapped in a <div class="wp-html-segment">. If this interferes with your layout (e.g. inside a flex or grid container), you can make the wrapper transparent:

wp-shortcode .wp-html-segment {
  display: contents;
}

API reference

provideShortcodes(definitions)

provideShortcodes(definitions: ShortcodeDefinition[]): Provider

Registers shortcode → component mappings. Safe to call multiple times.

interface ShortcodeDefinition {
  tag: string;           // e.g. 'gallery'
  component: Type<unknown>;
}

<wp-shortcode>

@Component({ selector: 'wp-shortcode', ... })
export class WpShortcodeComponent {
  content = input<string>('');   // HTML string containing WP shortcodes
}

ShortcodeRegistry

@Injectable({ providedIn: 'root' })
export class ShortcodeRegistry {
  resolve(tag: string): Type<unknown> | null;
  register(tag: string, component: Type<unknown>): void;
}

parseShortcodes(content)

parseShortcodes(content: string): Segment[]

type Segment = HtmlSegment | ShortcodeToken;

interface HtmlSegment    { type: 'html';      html: string; }
interface ShortcodeToken { type: 'shortcode'; tag: string; attrs: Record<string, string>; inner: string; }

parseAttributes(str)

parseAttributes(str: string): Record<string, string>

Building & publishing

# build the library
ng build

# publish from the dist folder
cd ../../dist/tomaszatoo/wp-shortcode
npm publish

License

MIT