t pages.
*
* @param string|string[] $template The specific template filename or array of templates to match.
* @return bool True on success, false on failure.
*/
function is_page_template( $template = '' ) {
if ( ! is_singular() ) {
return false;
}
$page_template = get_page_template_slug( get_queried_object_id() );
if ( empty( $template ) ) {
return (bool) $page_template;
}
if ( $template === $page_template ) {
return true;
}
if ( is_array( $template ) ) {
if ( ( in_array( 'default', $template, true ) && ! $page_template )
|| in_array( $page_template, $template, true )
) {
return true;
}
}
return ( 'default' === $template && ! $page_template );
}
/**
* Gets the specific template filename for a given post.
*
* @since 3.4.0
* @since 4.7.0 Now works with any post type, not just pages.
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @return string|false Page template filename. Returns an empty string when the default page template
* is in use. Returns false if the post does not exist.
*/
function get_page_template_slug( $post = null ) {
$post = get_post( $post );
if ( ! $post ) {
return false;
}
$template = get_post_meta( $post->ID, '_wp_page_template', true );
if ( ! $template || 'default' === $template ) {
return '';
}
return $template;
}
/**
* Retrieves formatted date timestamp of a revision (linked to that revisions's page).
*
* @since 2.6.0
*
* @param int|WP_Post $revision Revision ID or revision object.
* @param bool $link Optional. Whether to link to revision's page. Default true.
* @return string|false i18n formatted datetimestamp or localized 'Current Revision'.
*/
function wp_post_revision_title( $revision, $link = true ) {
$revision = get_post( $revision );
if ( ! $revision ) {
return $revision;
}
if ( ! in_array( $revision->post_type, array( 'post', 'page', 'revision' ), true ) ) {
return false;
}
/* translators: Revision date format, see https://www.php.net/manual/datetime.format.php */
$datef = _x( 'F j, Y @ H:i:s', 'revision date format' );
/* translators: %s: Revision date. */
$autosavef = __( '%s [Autosave]' );
/* translators: %s: Revision date. */
$currentf = __( '%s [Current Revision]' );
$date = date_i18n( $datef, strtotime( $revision->post_modified ) );
$edit_link = get_edit_post_link( $revision->ID );
if ( $link && current_user_can( 'edit_post', $revision->ID ) && $edit_link ) {
$date = "$date";
}
if ( ! wp_is_post_revision( $revision ) ) {
$date = sprintf( $currentf, $date );
} elseif ( wp_is_post_autosave( $revision ) ) {
$date = sprintf( $autosavef, $date );
}
return $date;
}
/**
* Retrieves formatted date timestamp of a revision (linked to that revisions's page).
*
* @since 3.6.0
*
* @param int|WP_Post $revision Revision ID or revision object.
* @param bool $link Optional. Whether to link to revision's page. Default true.
* @return string|false gravatar, user, i18n formatted datetimestamp or localized 'Current Revision'.
*/
function wp_post_revision_title_expanded( $revision, $link = true ) {
$revision = get_post( $revision );
if ( ! $revision ) {
return $revision;
}
if ( ! in_array( $revision->post_type, array( 'post', 'page', 'revision' ), true ) ) {
return false;
}
$author = get_the_author_meta( 'display_name', $revision->post_author );
/* translators: Revision date format, see https://www.php.net/manual/datetime.format.php */
$datef = _x( 'F j, Y @ H:i:s', 'revision date format' );
$gravatar = get_avatar( $revision->post_author, 24 );
$date = date_i18n( $datef, strtotime( $revision->post_modified ) );
$edit_link = get_edit_post_link( $revision->ID );
if ( $link && current_user_can( 'edit_post', $revision->ID ) && $edit_link ) {
$date = "$date";
}
$revision_date_author = sprintf(
/* translators: Post revision title. 1: Author avatar, 2: Author name, 3: Time ago, 4: Date. */
__( '%1$s %2$s, %3$s ago (%4$s)' ),
$gravatar,
$author,
human_time_diff( strtotime( $revision->post_modified_gmt ) ),
$date
);
/* translators: %s: Revision date with author avatar. */
$autosavef = __( '%s [Autosave]' );
/* translators: %s: Revision date with author avatar. */
$currentf = __( '%s [Current Revision]' );
if ( ! wp_is_post_revision( $revision ) ) {
$revision_date_author = sprintf( $currentf, $revision_date_author );
} elseif ( wp_is_post_autosave( $revision ) ) {
$revision_date_author = sprintf( $autosavef, $revision_date_author );
}
/**
* Filters the formatted author and date for a revision.
*
* @since 4.4.0
*
* @param string $revision_date_author The formatted string.
* @param WP_Post $revision The revision object.
* @param bool $link Whether to link to the revisions page, as passed into
* wp_post_revision_title_expanded().
*/
return apply_filters( 'wp_post_revision_title_expanded', $revision_date_author, $revision, $link );
}
/**
* Displays a list of a post's revisions.
*
* Can output either a UL with edit links or a TABLE with diff interface, and
* restore action links.
*
* @since 2.6.0
*
* @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
* @param string $type 'all' (default), 'revision' or 'autosave'
*/
function wp_list_post_revisions( $post = 0, $type = 'all' ) {
$post = get_post( $post );
if ( ! $post ) {
return;
}
// $args array with (parent, format, right, left, type) deprecated since 3.6.
if ( is_array( $type ) ) {
$type = ! empty( $type['type'] ) ? $type['type'] : $type;
_deprecated_argument( __FUNCTION__, '3.6.0' );
}
$revisions = wp_get_post_revisions( $post->ID );
if ( ! $revisions ) {
return;
}
$rows = '';
foreach ( $revisions as $revision ) {
if ( ! current_user_can( 'read_post', $revision->ID ) ) {
continue;
}
$is_autosave = wp_is_post_autosave( $revision );
if ( ( 'revision' === $type && $is_autosave ) || ( 'autosave' === $type && ! $is_autosave ) ) {
continue;
}
$rows .= "\t
" . wp_post_revision_title_expanded( $revision ) . "\n";
}
echo "" . __( 'JavaScript must be enabled to use this feature.' ) . "
\n";
echo "';
}
/**
* Retrieves the parent post object for the given post.
*
* @since 5.7.0
*
* @param int|WP_Post|null $post Optional. Post ID or WP_Post object. Default is global $post.
* @return WP_Post|null Parent post object, or null if there isn't one.
*/
function get_post_parent( $post = null ) {
$wp_post = get_post( $post );
return ! empty( $wp_post->post_parent ) ? get_post( $wp_post->post_parent ) : null;
}
/**
* Returns whether the given post has a parent post.
*
* @since 5.7.0
*
* @param int|WP_Post|null $post Optional. Post ID or WP_Post object. Default is global $post.
* @return bool Whether the post has a parent post.
*/
function has_post_parent( $post = null ) {
return (bool) get_post_parent( $post );
}
able_name, $schema );
}
}
}
foreach ( $tables as $module => $table_group ) {
foreach ( $table_group as $table_name => $schema ) {
DB_Helper::create_table( $table_name, $schema );
}
}
}
/**
* Check if the schema is old style.
*
* @param array $arr Array of tables.
*/
public static function is_old_schema( &$arr ) {
$schema = [];
foreach ( array_keys( $arr ) as $key ) {
if ( is_int( $key ) ) {
$schema[] = $arr[ $key ];
unset( $arr[ $key ] );
}
}
return $schema;
}
/**
* Create options.
*/
private function create_options() {
$this->create_misc_options();
$this->create_general_options();
$this->create_titles_sitemaps_options();
$this->create_instant_indexing_options();
}
/**
* Create misc options.
*/
private function create_misc_options() {
// Update "known CPTs" list, so we can send notice about new ones later.
add_option( 'rank_math_known_post_types', Helper::get_accessible_post_types() );
$modules = [
'link-counter',
'analytics',
'seo-analysis',
'sitemap',
'rich-snippet',
'woocommerce',
'buddypress',
'bbpress',
'acf',
'web-stories',
'content-ai',
'instant-indexing',
];
// Role Manager.
$users = get_users( [ 'role__in' => [ 'administrator', 'editor', 'author', 'contributor' ] ] );
if ( count( $users ) > 1 ) {
$modules[] = 'role-manager';
}
// If AMP plugin is installed.
if ( function_exists( 'is_amp_endpoint' ) || class_exists( 'Better_AMP' ) || class_exists( 'Weeblramp_Api' ) || class_exists( 'AMPHTML' ) ) {
$modules[] = 'amp';
}
// If 404-monitor is active as plugin.
if ( false !== get_option( 'rank_math_monitor_version', false ) ) {
$modules[] = '404-monitor';
}
add_option( 'rank_math_modules', $modules );
add_option( 'rank_math_react_settings_ui', 'on', '', false );
self::create_tables( $modules );
}
/**
* Add defaults for general options.
*/
private function create_general_options() {
$post_types = Helper::get_accessible_post_types();
if ( isset( $post_types['attachment'] ) ) {
unset( $post_types['attachment'] );
}
add_option(
'rank-math-options-general',
$this->do_filter(
'settings/defaults/general',
[
'strip_category_base' => 'off',
'attachment_redirect_urls' => 'on',
'attachment_redirect_default' => get_home_url(),
'nofollow_external_links' => 'off',
'nofollow_image_links' => 'off',
'new_window_external_links' => 'on',
'add_img_alt' => 'off',
'img_alt_format' => ' %filename%',
'add_img_title' => 'off',
'img_title_format' => '%title% %count(title)%',
'breadcrumbs' => 'off',
'breadcrumbs_separator' => '-',
'breadcrumbs_home' => 'on',
'breadcrumbs_home_label' => esc_html__( 'Home', 'rank-math' ),
/* translators: Archive title */
'breadcrumbs_archive_format' => esc_html__( 'Archives for %s', 'rank-math' ),
/* translators: Search query term */
'breadcrumbs_search_format' => esc_html__( 'Results for %s', 'rank-math' ),
'breadcrumbs_404_label' => esc_html__( '404 Error: page not found', 'rank-math' ),
'breadcrumbs_ancestor_categories' => 'off',
'breadcrumbs_blog_page' => 'off',
'404_monitor_mode' => 'simple',
'404_monitor_limit' => 100,
'404_monitor_ignore_query_parameters' => 'on',
'redirections_header_code' => '301',
'redirections_debug' => 'off',
'console_caching_control' => '90',
'console_email_reports' => 'on',
'console_email_frequency' => 'monthly',
'wc_remove_product_base' => 'off',
'wc_remove_category_base' => 'off',
'wc_remove_category_parent_slugs' => 'off',
'rss_before_content' => '',
'rss_after_content' => '',
'wc_remove_generator' => 'on',
'remove_shop_snippet_data' => 'on',
'frontend_seo_score' => 'off',
'frontend_seo_score_post_types' => [ 'post' ],
'frontend_seo_score_position' => 'top',
'setup_mode' => 'advanced',
'content_ai_post_types' => array_keys( $post_types ),
'content_ai_country' => 'all',
'content_ai_tone' => 'Formal',
'content_ai_audience' => 'General Audience',
'content_ai_language' => Helper::content_ai_default_language(),
'analytics_stats' => 'on',
'toc_block_title' => 'Table of Contents',
'toc_block_list_style' => 'ul',
'llms_post_types' => array_keys( $post_types ),
]
)
);
}
/**
* Add default values.
*/
private function create_titles_sitemaps_options() {
$sitemap = [
'items_per_page' => 200,
'include_images' => 'on',
'include_featured_image' => 'off',
'exclude_roles' => $this->get_excluded_roles(),
'html_sitemap' => 'on',
'html_sitemap_display' => 'shortcode',
'html_sitemap_sort' => 'published',
'html_sitemap_seo_titles' => 'titles',
'authors_sitemap' => 'on',
];
$titles = [
'noindex_empty_taxonomies' => 'on',
'title_separator' => '-',
'capitalize_titles' => 'off',
'twitter_card_type' => 'summary_large_image',
'knowledgegraph_type' => class_exists( 'Easy_Digital_Downloads' ) || class_exists( 'WooCommerce' ) ? 'company' : 'person',
'knowledgegraph_name' => get_bloginfo( 'name' ),
'website_name' => get_bloginfo( 'name' ),
'local_business_type' => 'Organization',
'local_address_format' => '{address} {locality}, {region} {postalcode}',
'opening_hours' => $this->get_opening_hours(),
'opening_hours_format' => 'off',
'homepage_title' => '%sitename% %page% %sep% %sitedesc%',
'homepage_description' => '',
'homepage_custom_robots' => 'off',
'disable_author_archives' => 'off',
'url_author_base' => 'author',
'author_custom_robots' => 'on',
'author_robots' => [ 'noindex' ],
'author_archive_title' => '%name% %sep% %sitename% %page%',
'author_add_meta_box' => 'on',
'disable_date_archives' => 'on',
'date_archive_title' => '%date% %page% %sep% %sitename%',
'search_title' => '%search_query% %page% %sep% %sitename%',
'404_title' => 'Page Not Found %sep% %sitename%',
'date_archive_robots' => [ 'noindex' ],
'noindex_search' => 'on',
'noindex_archive_subpages' => 'off',
'noindex_password_protected' => 'off',
];
$this->create_post_type_options( $titles, $sitemap );
$this->create_taxonomy_options( $titles, $sitemap );
add_option( 'rank-math-options-titles', $this->do_filter( 'settings/defaults/titles', $titles ) );
add_option( 'rank-math-options-sitemap', $this->do_filter( 'settings/defaults/sitemap', $sitemap ) );
}
/**
* Create post type options.
*
* @param array $titles Hold title settings.
* @param array $sitemap Hold sitemap settings.
*/
private function create_post_type_options( &$titles, &$sitemap ) {
$post_types = Helper::get_accessible_post_types();
array_push( $post_types, 'product', 'web-story' );
$titles['pt_download_default_rich_snippet'] = 'product';
$titles['author_slack_enhanced_sharing'] = 'on';
foreach ( $post_types as $post_type ) {
$defaults = $this->get_post_type_defaults( $post_type );
$titles[ 'pt_' . $post_type . '_title' ] = '%title% %sep% %sitename%';
$titles[ 'pt_' . $post_type . '_description' ] = '%excerpt%';
$titles[ 'pt_' . $post_type . '_robots' ] = $defaults['robots'];
$titles[ 'pt_' . $post_type . '_custom_robots' ] = $defaults['is_custom'];
$titles[ 'pt_' . $post_type . '_default_rich_snippet' ] = $defaults['rich_snippet'];
$titles[ 'pt_' . $post_type . '_default_article_type' ] = $defaults['article_type'];
$titles[ 'pt_' . $post_type . '_default_snippet_name' ] = '%seo_title%';
$titles[ 'pt_' . $post_type . '_default_snippet_desc' ] = '%seo_description%';
if ( $this->has_archive( $post_type ) ) {
$titles[ 'pt_' . $post_type . '_archive_title' ] = '%title% %page% %sep% %sitename%';
}
// Slack enhanced sharing is off by default, except for posts, pages, products, and downloads.
$titles[ 'pt_' . $post_type . '_slack_enhanced_sharing' ] = 'off';
if ( in_array( $post_type, [ 'post', 'page', 'product', 'download' ], true ) ) {
$titles[ 'pt_' . $post_type . '_slack_enhanced_sharing' ] = 'on';
}
if ( in_array( $post_type, [ 'attachment', 'web-story' ], true ) ) {
$sitemap[ 'pt_' . $post_type . '_sitemap' ] = 'off';
$titles[ 'pt_' . $post_type . '_add_meta_box' ] = 'off';
continue;
}
$sitemap[ 'pt_' . $post_type . '_sitemap' ] = 'on';
$titles[ 'pt_' . $post_type . '_ls_use_fk' ] = 'titles';
$titles[ 'pt_' . $post_type . '_add_meta_box' ] = 'on';
$titles[ 'pt_' . $post_type . '_bulk_editing' ] = 'editing';
$titles[ 'pt_' . $post_type . '_link_suggestions' ] = 'on';
// Primary Taxonomy.
$taxonomy_hash = [
'post' => 'category',
'product' => 'product_cat',
];
if ( isset( $taxonomy_hash[ $post_type ] ) ) {
$titles[ 'pt_' . $post_type . '_primary_taxonomy' ] = $taxonomy_hash[ $post_type ];
}
}
}
/**
* Get robots default for post type.
*
* @param string $post_type Post type.
* @return array
*/
private function get_post_type_defaults( $post_type ) {
$rich_snippets = [
'post' => 'article',
'page' => 'article',
'product' => 'product',
'download' => 'product',
'web-story' => 'article',
];
$defaults = [
'robots' => [ 'index' ],
'is_custom' => 'off',
'rich_snippet' => isset( $rich_snippets[ $post_type ] ) ? $rich_snippets[ $post_type ] : 'off',
'article_type' => 'post' === $post_type ? 'BlogPosting' : 'Article',
];
if ( 'attachment' === $post_type ) {
$defaults['is_custom'] = 'on';
$defaults['robots'] = [ 'noindex' ];
}
return $defaults;
}
/**
* Check post type has archive.
*
* @param string $post_type Post type.
* @return bool
*/
private function has_archive( $post_type ) {
$post_type_obj = get_post_type_object( $post_type );
return ! is_null( $post_type_obj ) && $post_type_obj->has_archive;
}
/**
* Create post type options.
*
* @param array $titles Hold title settings.
* @param array $sitemap Hold sitemap settings.
*/
private function create_taxonomy_options( &$titles, &$sitemap ) {
$taxonomies = Helper::get_accessible_taxonomies();
foreach ( $taxonomies as $taxonomy => $object ) {
$defaults = $this->get_taxonomy_defaults( $taxonomy );
$titles[ 'tax_' . $taxonomy . '_title' ] = '%term% %sep% %sitename%';
$titles[ 'tax_' . $taxonomy . '_robots' ] = $defaults['robots'];
$titles[ 'tax_' . $taxonomy . '_add_meta_box' ] = $defaults['metabox'];
$titles[ 'tax_' . $taxonomy . '_custom_robots' ] = $defaults['is_custom'];
$titles[ 'tax_' . $taxonomy . '_description' ] = '%term_description%';
$titles[ 'tax_' . $taxonomy . '_slack_enhanced_sharing' ] = 'on';
$titles[ 'tax_' . $taxonomy . '_bulk_editing' ] = 0;
$sitemap[ 'tax_' . $taxonomy . '_sitemap' ] = 'category' === $taxonomy ? 'on' : 'off';
if ( substr( $taxonomy, 0, 3 ) === 'pa_' ) {
$titles[ 'remove_' . $taxonomy . '_snippet_data' ] = 'on';
}
}
$titles['remove_product_cat_snippet_data'] = 'on';
$titles['remove_product_tag_snippet_data'] = 'on';
}
/**
* Get robots default for post type.
*
* @param string $taxonomy Taxonomy.
* @return array
*/
private function get_taxonomy_defaults( $taxonomy ) {
$defaults = [
'robots' => [ 'index' ],
'is_custom' => 'off',
'metabox' => 'category' === $taxonomy ? 'on' : 'off',
];
if ( in_array( $taxonomy, [ 'post_tag', 'post_format', 'product_tag' ], true ) ) {
$defaults['is_custom'] = 'on';
$defaults['robots'] = [ 'noindex' ];
}
return $defaults;
}
/**
* Create capabilities.
*/
private function set_capabilities() {
$admin = get_role( 'administrator' );
if ( ! is_null( $admin ) ) {
$admin->add_cap( 'rank_math_edit_htaccess', true );
}
Capability_Manager::get()->create_capabilities();
}
/**
* Create cron jobs.
*/
public function create_cron_jobs() {
$midnight = strtotime( 'tomorrow midnight' );
foreach ( $this->get_cron_jobs() as $job => $recurrence ) {
if ( ! wp_next_scheduled( "rank_math/{$job}" ) ) {
$timestamp = 'content-ai/update_prompts' === $job ? $midnight + wp_rand( 60, 86400 ) : $midnight;
wp_schedule_event( $timestamp, $this->do_filter( "{$job}_recurrence", $recurrence ), "rank_math/{$job}" );
}
}
}
/**
* Remove cron jobs.
*/
private function remove_cron_jobs() {
foreach ( $this->get_cron_jobs() as $job => $recurrence ) {
wp_clear_scheduled_hook( "rank_math/{$job}" );
}
}
/**
* Get cron jobs.
*
* @return array
*/
private function get_cron_jobs() {
return [
'redirection/clean_trashed' => 'daily', // Add cron for cleaning trashed redirects.
'links/internal_links' => 'daily', // Add cron for counting links.
'content-ai/update_prompts' => 'daily', // Add cron for updating the prompts data.
];
}
/**
* Get opening hours.
*
* @return array
*/
private function get_opening_hours() {
$hours = [];
$days = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ];
foreach ( $days as $day ) {
$hours[] = [
'day' => $day,
'time' => '09:00-17:00',
];
}
return $hours;
}
/**
* Get roles to exclude.
*
* @return array
*/
private function get_excluded_roles() {
$roles = Helper::get_roles();
unset( $roles['administrator'], $roles['editor'], $roles['author'] );
return array_keys( $roles );
}
/**
* Clear rewrite rules.
*
* @param bool $activate True for plugin activation, false for de-activation.
*/
private function clear_rewrite_rules( $activate ) {
if ( is_multisite() && ms_is_switched() ) {
delete_option( 'rewrite_rules' );
Helper::schedule_flush_rewrite();
return;
}
// On activation.
if ( $activate ) {
Helper::schedule_flush_rewrite();
return;
}
// On deactivation.
add_action( 'shutdown', 'flush_rewrite_rules' );
}
/**
* Add defaults for the Instant Indexing module options.
*
* @return void
*/
private function create_instant_indexing_options() {
add_option(
'rank-math-options-instant-indexing',
$this->do_filter(
'settings/defaults/instant-indexing',
[
'bing_post_types' => [ 'post', 'page' ],
]
)
);
}
}