Skip to content

Early-bird lifetime licence: $199 once, for the first 200 buyers only. See the offer

init

Fires once WordPress has loaded and the current user is known, before any headers are sent. The usual place to register post types.

  • Type Action
  • From WordPress
  • Since 1.5.0
  • Fired in wp-settings.php

When it fires

init runs on every request (front end, admin, AJAX, REST API and cron) once WordPress, your plugins and your theme have loaded. The current user has been set up by now, so is_user_logged_in() and current_user_can() work.

Nothing has been sent to the browser yet, but the main query hasn't run either, so conditional tags such as is_page() or is_single() don't work here. Use template_redirect for anything that depends on the page being viewed.

Parameters

None. Your callback takes no arguments.

Example: Register a custom post type

PHP
add_action( 'init', function () {
	register_post_type(
		'testimonial',
		array(
			'labels'       => array(
				'name'          => __( 'Testimonials', 'my-snippets' ),
				'singular_name' => __( 'Testimonial', 'my-snippets' ),
			),
			'public'       => true,
			'has_archive'  => true,
			'show_in_rest' => true,
			'menu_icon'    => 'dashicons-format-quote',
			'supports'     => array( 'title', 'editor', 'thumbnail' ),
		)
	);
} );

Good to know

  • After registering a new post type, go to Settings > Permalinks and click Save once, so its URLs start working.
  • init runs on every request, so keep the callback light. Move slow work to a more specific hook or a scheduled event.
  • Core uses init with its own priorities too (widgets are set up at priority 1), so stick to the default 10 unless you need to run before or after something specific.

Move your snippets over this afternoon.

Importing changes nothing until you switch over, and your old shortcodes keep working.