'',
'dismissible' => false,
'id' => '',
'additional_classes' => array(),
'attributes' => array(),
'paragraph_wrap' => true,
);
$args = wp_parse_args( $args, $defaults );
$args = apply_filters( 'wp_admin_notice_args', $args, $message ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- replicates WordPress core's own wp_admin_notice_args filter for compatibility with code hooking the real core filter.
$id = '';
$classes = 'notice';
$attributes = '';
if ( is_string( $args['id'] ) ) {
$trimmed_id = trim( $args['id'] );
if ( '' !== $trimmed_id ) {
$id = 'id="' . $trimmed_id . '" ';
}
}
if ( is_string( $args['type'] ) ) {
$type = trim( $args['type'] );
if ( '' !== $type ) {
$classes .= ' notice-' . $type;
}
}
if ( true === $args['dismissible'] ) {
$classes .= ' is-dismissible';
}
if ( is_array( $args['additional_classes'] ) && ! empty( $args['additional_classes'] ) ) {
$classes .= ' ' . implode( ' ', $args['additional_classes'] );
}
if ( is_array( $args['attributes'] ) && ! empty( $args['attributes'] ) ) {
foreach ( $args['attributes'] as $attr => $val ) {
if ( is_bool( $val ) ) {
$attributes .= $val ? ' ' . $attr : '';
} elseif ( is_int( $attr ) ) {
$attributes .= ' ' . esc_attr( trim( $val ) );
} elseif ( $val ) {
$attributes .= ' ' . $attr . '="' . esc_attr( trim( $val ) ) . '"';
}
}
}
if ( false !== $args['paragraph_wrap'] ) {
$message = "
$message
";
}
$markup = sprintf( '%4$s
', $id, $classes, $attributes, $message );
return apply_filters( 'wp_admin_notice_markup', $markup, $message, $args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- replicates WordPress core's own wp_admin_notice_markup filter for compatibility with code hooking the real core filter.
}
}
if ( ! function_exists( 'ao_autoload_values_to_autoload' ) ) {
/**
* Gets the values that should be considered for autoloading from the options table.
* Uses WP 6.6's wp_autoload_values_to_autoload() if available, otherwise falls back to
* the pre-6.6 'yes'/'no' autoload values.
*
* @return string[]
*/
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- ao_ is this plugin's established short-form prefix.
function ao_autoload_values_to_autoload() {
if ( function_exists( 'wp_autoload_values_to_autoload' ) ) {
// phpcs:ignore PluginCheck.CodeAnalysis.Compatibility.wp_function_not_compatible_with_requires_wp -- guarded by function_exists(); only reached on WP 6.6+ where this function exists. NOTE: sniff code unconfirmed, pending re-scan verification.
return wp_autoload_values_to_autoload();
}
return array( 'yes' );
}
}
if ( ! function_exists( 'ao_admin_notice' ) ) {
/**
* Outputs an admin notice. Uses WP 6.4's wp_admin_notice() if available,
* otherwise falls back to a backport of it.
*
* @param string $message The notice message (HTML allowed).
* @param array $args Optional arguments: type, dismissible, id, additional_classes, attributes, paragraph_wrap.
* @return void
*/
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- ao_ is this plugin's established short-form prefix.
function ao_admin_notice( $message, $args = array() ) {
if ( function_exists( 'wp_admin_notice' ) ) {
// phpcs:ignore PluginCheck.CodeAnalysis.Compatibility.wp_function_not_compatible_with_requires_wp -- guarded by function_exists(); only reached on WP 6.4+ where this function exists.
wp_admin_notice( $message, $args );
return;
}
do_action( 'wp_admin_notice', $message, $args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- replicates WordPress core's own wp_admin_notice action for compatibility with code hooking the real core action.
echo wp_kses_post( ao_get_admin_notice( $message, $args ) );
}
}
if ( ! function_exists( 'ao_get_upgrade_url' ) ) {
/**
* Build a Pro upgrade URL tagged with an `ao_src` attribution label.
*
* Every in-plugin "Upgrade to Pro" nudge should link out through this
* helper rather than hardcoding the pricing URL, so the destination
* domain stays in one place and each link is tagged with a static,
* human-chosen label identifying which nudge sent the visitor.
*
* `ao_src` is not a tracking/analytics parameter: it carries no site
* URL, user ID, email, license key or plugin version, requires no
* JavaScript, network request, cookie or storage, and only reaches the
* destination site when the user chooses to click the link. See
* docs/ao-src-labels.md for the full list of registered labels.
*
* @param string $placement Registered label for this nudge, e.g. 'seo-manager-pro-options'.
* Must match /^[a-z0-9-]{1,40}$/; an invalid label is silently
* dropped and the URL is returned without ao_src.
* @param array $args Optional extra query args to merge in (e.g. an existing
* plan or product parameter). Never pass tracking parameters
* (utm_*, gclid, etc.) here.
* @return string Unescaped URL. Callers must wrap the result in esc_url().
*/
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- ao_ is this plugin's established short-form prefix.
function ao_get_upgrade_url( string $placement, array $args = array() ) {
$url = ADMINOPTIMIZER_UPGRADE_URL;
if ( ! empty( $args ) ) {
$url = add_query_arg( $args, $url );
}
if ( 1 === preg_match( '/^[a-z0-9-]{1,40}$/', $placement ) ) {
$url = add_query_arg( array( 'ao_src' => $placement ), $url );
}
return $url;
}
}