Skip to content

EmDash for WordPress Developers

EmDash brings familiar WordPress concepts—posts, pages, taxonomies, menus, widgets, and a media library—into a modern Astro stack. Your content management knowledge transfers directly.

The concepts you know from WordPress are first-class features in EmDash:

  • Collections work like Custom Post Types—define your content structure, query it in templates
  • Taxonomies work the same way—hierarchical (like categories) and flat (like tags)
  • Menus with drag-and-drop ordering and nested items
  • Widget Areas for sidebars and dynamic content regions
  • Media library with upload, organization, and image management
  • Admin UI that content editors can use without touching code

The implementation changes, but the mental model stays the same:

TypeScript instead of PHP

Templates are Astro components. The syntax is cleaner, but the concept is the same: server code that outputs HTML.

Content APIs instead of WP_Query

Query functions like getEmDashCollection() replace WP_Query. No SQL, just function calls.

File-based routing

Files in src/pages/ become URLs. No rewrite rules or template hierarchy to memorize.

Components instead of template parts

Import and use components. Same idea as get_template_part(), better organization.

WordPressEmDashNotes
Custom Post TypesCollectionsDefine via admin UI or API
WP_QuerygetEmDashCollection()Filters, limits, taxonomy queries
get_post()getEmDashEntry()Returns entry or null
Categories/TagsTaxonomiesHierarchical support preserved
register_nav_menus()getMenu()First-class menu support
register_sidebar()getWidgetArea()First-class widget areas
bloginfo('name')getSiteSetting("title")Site settings API
the_content()<PortableText />Structured content rendering
ShortcodesPortable Text blocksCustom components
add_action/filter()Plugin hookscontent:beforeSave, etc.
wp_optionsctx.kvKey-value storage
Theme directorysrc/ directoryComponents, layouts, pages
functions.phpastro.config.mjs + EmDash configBuild and runtime config

WordPress queries use WP_Query or helper functions. EmDash uses typed query functions.

archive.php
<?php
$posts = new WP_Query([
'post_type' => 'post',
'posts_per_page' => 10,
'post_status' => 'publish',
'category_name' => 'news',
]);
while ($posts->have_posts()) :
$posts->the_post();
?>
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
<?php endwhile; ?>
single.php
<?php
$post = get_post($id);
?>
<article>
<h1><?php echo $post->post_title; ?></h1>
<?php echo apply_filters('the_content', $post->post_content); ?>
</article>

WordPress uses a template hierarchy to select which file renders a page. Astro uses explicit file-based routing.

WordPress TemplateEmDash Equivalent
index.phpsrc/pages/index.astro
single.phpsrc/pages/posts/[slug].astro
single-{type}.phpsrc/pages/{type}/[slug].astro
page.phpsrc/pages/pages/[slug].astro
archive.phpsrc/pages/posts/index.astro
archive-{type}.phpsrc/pages/{type}/index.astro
category.phpsrc/pages/categories/[slug].astro
tag.phpsrc/pages/tags/[slug].astro
search.phpsrc/pages/search.astro
404.phpsrc/pages/404.astro
header.php / footer.phpsrc/layouts/Base.astro
sidebar.phpsrc/components/Sidebar.astro

WordPress template parts become Astro components:

functions.php / template
// In template:
get_template_part('template-parts/content', 'post');
// template-parts/content-post.php:
<article class="post">
<h2><?php the_title(); ?></h2>
<?php the_excerpt(); ?>
</article>

EmDash has first-class menu support with automatic URL resolution:

header.php
<?php
wp_nav_menu([
'theme_location' => 'primary',
'container' => 'nav',
]);
?>

Menus are created via the admin UI, seed files, or WordPress import.

Widget areas work like sidebars in WordPress:

sidebar.php
<?php if (is_active_sidebar('sidebar-1')) : ?>
<aside>
<?php dynamic_sidebar('sidebar-1'); ?>
</aside>
<?php endif; ?>

Site options and customizer settings map to getSiteSetting():

WordPressEmDash
bloginfo('name')getSiteSetting("title")
bloginfo('description')getSiteSetting("tagline")
get_custom_logo()getSiteSetting("logo")
get_option('date_format')getSiteSetting("dateFormat")
home_url()Astro.site
import { getSiteSetting } from "emdash";
const title = await getSiteSetting("title");
const logo = await getSiteSetting("logo"); // Returns { mediaId, alt, url }

Taxonomies work the same conceptually—hierarchical (like categories) or flat (like tags):

import { getTaxonomyTerms, getEntryTerms, getTerm } from "emdash";
// Get all categories
const categories = await getTaxonomyTerms("categories");
// Get a specific term
const news = await getTerm("categories", "news");
// Get terms for a post
const postCategories = await getEntryTerms("posts", postId, "categories");

WordPress hooks (add_action, add_filter) become EmDash plugin hooks:

WordPress HookEmDash HookPurpose
save_postcontent:beforeSaveModify content before saving
the_contentPortableText componentsTransform rendered content
pre_get_postsQuery optionsFilter queries
wp_headLayout <head>Add head content
wp_footerLayout before </body>Add footer content

Type Safety

TypeScript throughout. Collections, queries, and components are fully typed. No more guessing field names or return types.

Performance

No PHP overhead. Static generation by default. Server rendering when needed. Edge deployment ready.

Modern DX

Hot module replacement. Component-based architecture. Modern tooling (Vite, TypeScript, ESLint).

Git-based Deployments

Code and templates in git. Content in the database. No FTP, no file permissions, no hacked sites.

EmDash generates secure preview URLs with HMAC-signed tokens. Content editors can preview drafts without logging into production—share a link, not credentials.

WordPress plugin conflicts disappear. EmDash plugins run in isolated contexts with explicit APIs. No global state pollution.

Content editors use the EmDash admin panel, similar to wp-admin:

  • Dashboard with recent activity
  • Collection listings with search, filter, and bulk actions
  • Rich editor for content (Portable Text, not Gutenberg)
  • Media library with drag-and-drop upload
  • Menu builder with drag-and-drop ordering
  • Widget area editor for sidebar content

The editing experience is familiar. The technology underneath is modern.

EmDash imports WordPress content directly:

  1. Export from WordPress (Tools → Export)
  2. Upload the .xml file in EmDash’s admin
  3. Map post types to collections
  4. Import content and media

Posts, pages, taxonomies, menus, and media transfer. Gutenberg blocks convert to Portable Text. Custom fields are analyzed and mapped.

See the WordPress Migration Guide for complete instructions.