array(), 'em' => array(), 'b' => array(), 'i' => array(), 'u' => array(), 'span' => array( 'class' => true ), 'div' => array( 'class' => true ), ) ); /** * Filters the footer acknowledgment address before tokens are resolved. * * Companion to acknowledgify_footer_link_text, for sending each * language to a different destination. The returned value still goes * through esc_url(), so an unsafe scheme is rejected as usual. * * @param string $url Stored link address, tokens unresolved. * @param string $placement_selector auto_insert, shortcode or php_snippet. */ $url = (string) apply_filters( 'acknowledgify_footer_link_url', (string) Helper::get_setting( 'footer_link_url' ), $placement_selector ); $link_url = esc_url( Tokens::resolve( $url ) ); // An anchor with no text is unusable and unreadable to a screen // reader, and one with no destination is not a link. Either means the // user has cleared the field, so render nothing at all. if ( '' === trim( wp_strip_all_tags( $link_text ) ) || '' === $link_url ) { return ''; } $custom_class = (string) Helper::get_setting( 'footer_custom_class', '' ); // ack-footer-link and any custom class are the stable hooks external // CSS targets, so they are emitted unconditionally in both style modes. $classes = trim( 'ack-footer-link ' . $custom_class ); $attributes = array( 'class="' . esc_attr( $classes ) . '"' ); /** * Filters the rel attribute values on the footer acknowledgment link. * * Defaults to nofollow to qualify distributed credit links. Google's * link-spam policy includes widely distributed footer links among its * examples. This default is not a blanket compliance guarantee. * * Return an array of rel keywords, for example array( 'sponsored' ) * for a paid credit, or an empty array to output a followed link. * noopener is always added afterwards and cannot be removed, because * the link opens in a new tab. * * @param string[] $rel Rel keywords. Default array( 'nofollow' ). * @param string $placement_selector auto_insert, shortcode or php_snippet. */ $rel = apply_filters( 'acknowledgify_footer_link_rel', array( 'nofollow' ), $placement_selector ); // Keep only well-formed keywords, whatever a filter returned. A rel // keyword is a bare token, so anything else is discarded rather than // escaped into the attribute. $rel = array_filter( array_map( 'strtolower', array_filter( (array) $rel, 'is_string' ) ), static function ( $keyword ) { return (bool) preg_match( '/^[a-z][a-z0-9-]*$/', $keyword ); } ); $rel[] = 'noopener'; $rel = array_values( array_unique( $rel ) ); $link_attributes = array( 'href="' . $link_url . '"', 'target="_blank"', 'rel="' . esc_attr( implode( ' ', $rel ) ) . '"', ); if ( 'plugin' === Helper::get_setting( 'footer_style_mode' ) ) { $text_color = Helper::get_setting( 'footer_text_color' ); $font_size = Helper::get_setting( 'footer_font_size' ); $bg_color = Helper::get_setting( 'footer_bg_color' ); $alignment = Helper::get_setting( 'footer_alignment' ); $wrapper_styles = array( 'color:' . $text_color, 'font-size:' . $font_size, ); // Both are optional; emit nothing when unset so the theme decides. if ( '' !== $bg_color ) { $wrapper_styles[] = 'background-color:' . $bg_color; } if ( 'inherit' !== $alignment ) { $wrapper_styles[] = 'text-align:' . $alignment; } $attributes[] = 'style="' . esc_attr( implode( '; ', $wrapper_styles ) . ';' ) . '"'; /* * Colour and size must also be set on the anchor. Themes style * "a { color: ... }" directly, which beats a colour inherited from * the wrapper, so setting it only on the wrapper meant the chosen * colour never reached the visible link text. */ $link_attributes[] = 'style="' . esc_attr( 'color:' . $text_color . '; font-size:' . $font_size . ';' ) . '"'; } /** * Filters the wrapper element for the footer acknowledgment. * * Defaults to div, which is what every existing site renders. A block * theme places wp_footer output after the footer template part and so * outside the theme's layout container; if that is awkward, switching * to span, or to the external style mode, usually resolves it. * * @param string $tag Element name. Default 'div'. * @param string $placement_selector auto_insert, shortcode or php_snippet. */ $tag = (string) apply_filters( 'acknowledgify_footer_wrapper_tag', 'div', $placement_selector ); $tag = preg_replace( '/[^a-z0-9]/', '', strtolower( $tag ) ); if ( '' === $tag ) { $tag = 'div'; } $output = sprintf( '<%1$s %2$s>%4$s', $tag, implode( ' ', $attributes ), implode( ' ', $link_attributes ), $link_text ); return wp_kses_post( $output ); } /** * Echo the acknowledgment markup for a placement. * * @param string $placement_selector auto_insert, shortcode or php_snippet. * @return void */ public static function footer_output( $placement_selector ) { // Already passed through wp_kses_post() in get_markup(). // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo self::get_markup( $placement_selector ); } }