Nate Arnold
Posted on September 10, 2020
I recently developed a WordPress theme for headless WordPress projects. This post is a simple explanation of the decisions that were made after implementing the theme on a few JAMstack projects.
Highlights
The index route forwards to the /wp-admin
login screen so there is no need for any front-end code:
<script type="text/javascript">
window.location.replace(window.location.protocol + "//" + window.location.hostname + "/wp-admin");
</script>
There is an example Custom Post Type already set up to display in the API as well as in the Graph if you are using WPGraphQL:
add_action( "init", "create_custom_post_type" );
function create_custom_post_type() {
register_post_type("custom_posts", // Register Custom Post Type
array(
"labels" => array(
"name" => "Custom Posts", // Rename these to suit
"singular_name" => "Custom Post",
"add_new" => "Add New",
"add_new_item" => "Add New Custom Post",
"edit" => "Edit",
"edit_item" => "Edit Custom Post",
"new_item" => "New Custom Post",
"view" => "View Custom Post",
"view_item" => "View Custom Post",
"search_items" => "Search Custom Posts",
"not_found" => "No Custom Posts found",
"not_found_in_trash" => "No Custom Posts found in Trash"
),
"menu_position" => 5,
"menu_icon" => "dashicons-awards",
"public" => true,
"show_in_rest" => true,
"show_ui" => true,
"show_in_menu" => true,
"publicly_queryable" => true,
"capability_type" => "page",
"hierarchical" => false,
"has_archive" => true,
"supports" => array("title","thumbnail","editor","revisions","excerpt","author"), // Other Options: trackbacks, custom-fields, page-attributes, comments, post-formats
"can_export" => true, // Allows export in Tools > Export
"taxonomies" => array(), // Add supported taxonomies,
"show_in_graphql" => true,
"graphql_single_name" => "CustomPost",
"graphql_plural_name" => "CustomPosts",
)
);
}
There are example Custom Shortcodes and Custom Taxonomies set up to display in the API as well as in the Graph:
function headless_shortcode( $atts , $content = null ) {
// Attributes
$args = shortcode_atts( array(
"link" => "",
"target" => "_self",
"rel" => "",
"class" => "",
), $atts );
return '<a href="' . $args['link'] . '" target="' . $args['target'] . '" rel="' . $args['rel'] . '" class="btn ' . $args['class'] . '">' . $content . '</a>';
}
add_shortcode( "headless", "headless_shortcode" );
add_filter("acf/format_value/type=textarea", "do_shortcode");
function headless_taxonomy() {
$labels = array(
"name" => "Taxonomies",
"singular_name" => "Taxonomy",
"menu_name" => "Taxonomies",
"all_items" => "All Taxonomies",
"parent_item" => "Parent Taxonomy",
"parent_item_colon" => "Parent Taxonomy:",
"new_item_name" => "New Taxonomy",
"add_new_item" => "Add Taxonomy",
"edit_item" => "Edit Taxonomy",
"update_item" => "Update Taxonomy",
"view_item" => "View Taxonomy",
"separate_items_with_commas" => "Separate Taxonomies with commas",
"add_or_remove_items" => "Add or remove Taxonomies",
"choose_from_most_used" => "Choose from the most used",
"popular_items" => "Popular Taxonomies",
"search_items" => "Search Taxonomies",
"not_found" => "Not Found",
"no_terms" => "No Taxonomies",
"items_list" => "Taxonomies list",
"items_list_navigation" => "Taxonomies list navigation",
);
$args = array(
"labels" => $labels,
"hierarchical" => false,
"public" => true,
"show_ui" => true,
"show_in_quick_edit" => false,
"meta_box_cb" => false,
"show_admin_column" => false,
"show_in_nav_menus" => false,
"show_tagcloud" => false,
"show_in_rest" => true,
"show_in_graphql" => true,
"graphql_single_name" => "Taxonomy",
"graphql_plural_name" => "Taxonomies",
);
register_taxonomy( "taxonomy", array( "page" ), $args );
}
add_action( "init", "headless_taxonomy", 0 );
There are some utility functions that help with reorganizing/removing menu items and disabling RSS:
function remove_menus() {
remove_menu_page( "index.php" ); //Dashboard
remove_menu_page( "jetpack" ); //Jetpack*
remove_menu_page( "edit-comments.php" ); //Comments
}
add_action( "admin_menu", "remove_menus" );
function headless_custom_menu_order( $menu_ord ) {
if ( !$menu_ord ) return true;
return array(
"edit.php?post_type=page", // Pages
"edit.php", // Posts
"edit.php?post_type=custom_posts", // Custom Post Type
"separator1", // First separator
"upload.php", // Media
"themes.php", // Appearance
"plugins.php", // Plugins
"users.php", // Users
"separator2", // Second separator
"tools.php", // Tools
"options-general.php", // Settings
"separator-last", // Last separator
);
}
add_filter( "custom_menu_order", "headless_custom_menu_order", 10, 1 );
add_filter( "menu_order", "headless_custom_menu_order", 10, 1 );
All ACF fields that are empty are nullified by default:
// Return `null` if an empty value is returned from ACF.
if (!function_exists("acf_nullify_empty")) {
function acf_nullify_empty($value, $post_id, $field) {
if (empty($value)) {
return null;
}
return $value;
}
}
add_filter("acf/format_value", "acf_nullify_empty", 100, 3);
Headless is available over on GitHub. Download it, peruse it, use it and let me know what you think!
Posted on September 10, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.