__( 'Display title', '4wp-faq' ), self::META_SEO_TITLE => __( 'SEO title', '4wp-faq' ), self::META_SEO_DESC => __( 'SEO description', '4wp-faq' ), ] as $key => $description ) { register_term_meta( $taxonomy, $key, [ 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field', 'auth_callback' => static function () { return current_user_can( 'manage_categories' ); }, 'description' => $description, ] ); } } /** * Fields on Add FAQ Category. */ public static function render_add_fields() { ?>

term_id, self::META_DISPLAY_TITLE, true ); $seo = (string) get_term_meta( $term->term_id, self::META_SEO_TITLE, true ); $desc = (string) get_term_meta( $term->term_id, self::META_SEO_DESC, true ); ?>

'forwp_display_title', self::META_SEO_TITLE => 'forwp_seo_title', self::META_SEO_DESC => 'forwp_seo_description', ]; foreach ( $fields as $meta_key => $post_key ) { if ( ! isset( $_POST[ $post_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing continue; } $value = sanitize_text_field( wp_unslash( (string) $_POST[ $post_key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing if ( '' === $value ) { delete_term_meta( $term_id, $meta_key ); } else { update_term_meta( $term_id, $meta_key, $value ); } } } /** * Active FAQ category term for the current request, if any. * * @return \WP_Term|null */ public static function get_active_term() { $slug = Faq_Filter::get_active_slug(); if ( '' === $slug ) { return null; } $taxonomy = Settings::get_taxonomy(); if ( ! taxonomy_exists( $taxonomy ) ) { return null; } $term = get_term_by( 'slug', $slug, $taxonomy ); return $term instanceof \WP_Term ? $term : null; } /** * Term for document H1 / title / meta — pretty category URLs only. * * @return \WP_Term|null */ public static function get_seo_term() { if ( ! Faq_Filter::is_pretty_category_request() ) { return null; } return self::get_active_term(); } /** * H1 / group heading: custom display title, else term name. * * @param \WP_Term $term Term. * @return string */ public static function get_display_title( $term ) { if ( ! $term instanceof \WP_Term ) { return ''; } $custom = get_term_meta( (int) $term->term_id, self::META_DISPLAY_TITLE, true ); if ( is_string( $custom ) && '' !== trim( $custom ) ) { return trim( $custom ); } return (string) $term->name; } /** * Document title for a category URL. * * @param \WP_Term $term Term. * @return string */ public static function get_seo_title( $term ) { if ( ! $term instanceof \WP_Term ) { return ''; } $custom = get_term_meta( (int) $term->term_id, self::META_SEO_TITLE, true ); if ( is_string( $custom ) && '' !== trim( $custom ) ) { return trim( $custom ); } return self::get_display_title( $term ); } /** * Meta description for a category URL. * * @param \WP_Term $term Term. * @return string */ public static function get_seo_description( $term ) { if ( ! $term instanceof \WP_Term ) { return ''; } $custom = get_term_meta( (int) $term->term_id, self::META_SEO_DESC, true ); return is_string( $custom ) ? trim( $custom ) : ''; } /** * @param string $title Current title. * @return string */ public static function filter_document_title( $title ) { $term = self::get_seo_term(); if ( ! $term instanceof \WP_Term ) { return $title; } $seo = self::get_seo_title( $term ); if ( '' === $seo ) { return $title; } $site = get_bloginfo( 'name', 'display' ); return '' !== $site ? $seo . ' – ' . $site : $seo; } /** * @param array $parts Title parts. * @return array */ public static function filter_document_title_parts( $parts ) { $term = self::get_seo_term(); if ( ! $term instanceof \WP_Term || ! is_array( $parts ) ) { return $parts; } $seo = self::get_seo_title( $term ); if ( '' !== $seo ) { $parts['title'] = $seo; } return $parts; } /** * @param string $title Title from Yoast / Rank Math. * @return string */ public static function filter_plain_title( $title ) { $term = self::get_seo_term(); if ( ! $term instanceof \WP_Term ) { return $title; } $seo = self::get_seo_title( $term ); if ( '' === $seo ) { return $title; } $site = get_bloginfo( 'name', 'display' ); if ( is_string( $site ) && '' !== $site && false === strpos( $seo, $site ) ) { return $seo . ' – ' . $site; } return $seo; } /** * @param string $description Description from Yoast / Rank Math. * @return string */ public static function filter_plain_description( $description ) { $term = self::get_seo_term(); if ( ! $term instanceof \WP_Term ) { return $description; } $desc = self::get_seo_description( $term ); return '' !== $desc ? $desc : $description; } /** * Native meta description when no SEO plugin owns the tag. */ public static function render_meta_description() { if ( defined( 'WPSEO_VERSION' ) || defined( 'RANK_MATH_VERSION' ) ) { return; } $term = self::get_seo_term(); if ( ! $term instanceof \WP_Term ) { return; } $desc = self::get_seo_description( $term ); if ( '' === $desc ) { return; } echo '' . "\n"; } /** * Replace the first core Heading H1 with the category display title. * * @param string $content Block HTML. * @param array $block Parsed block. * @return string */ public static function filter_heading_block( $content, $block ) { static $replaced = false; if ( $replaced || ! is_string( $content ) || '' === $content ) { return $content; } $term = self::get_seo_term(); if ( ! $term instanceof \WP_Term ) { return $content; } $attrs = isset( $block['attrs'] ) && is_array( $block['attrs'] ) ? $block['attrs'] : []; $level = isset( $attrs['level'] ) ? (int) $attrs['level'] : 2; if ( 1 !== $level ) { return $content; } $heading = self::get_display_title( $term ); if ( '' === $heading ) { return $content; } $updated = preg_replace( '/(]*>)(.*?)(<\/h1>)/is', '$1' . esc_html( $heading ) . '$3', $content, 1 ); if ( is_string( $updated ) && $updated !== $content ) { $replaced = true; return $updated; } return $content; } /** * Primary FAQ category term ID for a registry post. * * @param int $post_id Registry post ID. * @return int */ public static function get_primary_term_id( $post_id ) { $post_id = (int) $post_id; $ids = Registry_Content::get_post_term_ids( $post_id ); if ( empty( $ids ) ) { return 0; } $primary = (int) get_post_meta( $post_id, self::PRIMARY_META, true ); if ( $primary > 0 && in_array( $primary, $ids, true ) ) { return $primary; } return (int) $ids[0]; } }