diff --git a/src/wp-includes/abilities-api.php b/src/wp-includes/abilities-api.php
index 73ba658f3f10d..6beabfae3d41a 100644
--- a/src/wp-includes/abilities-api.php
+++ b/src/wp-includes/abilities-api.php
@@ -612,3 +612,116 @@ function wp_get_ability_categories(): array {
return $registry->get_all_registered();
}
+
+/**
+ * Marks an ability as deprecated and informs when it has been used.
+ *
+ * This function should be called from within a deprecated ability's execute callback
+ * to notify developers that they are using an obsolete ability. The function logs
+ * the deprecation and triggers a notice when WP_DEBUG is enabled.
+ *
+ * Example:
+ *
+ * function my_plugin_old_ability_callback( $input ) {
+ * _deprecated_ability( 'my-plugin/old-ability', '1.5.0', 'my-plugin/new-ability' );
+ * // Legacy implementation...
+ * }
+ *
+ * @since 7.0.0
+ *
+ * @param string $ability_name The name of the ability that is deprecated.
+ * @param string $version Optional. The version in which the ability was deprecated.
+ * Default empty string.
+ * @param string $replacement Optional. The name of the ability that should be used instead.
+ * Default empty string.
+ */
+function _deprecated_ability( string $ability_name, string $version = '', string $replacement = '' ): void {
+
+ /**
+ * Fires when a deprecated ability is called.
+ *
+ * @since 7.0.0
+ *
+ * @param string $ability_name The ability that was called.
+ * @param string $replacement The ability that should have been called.
+ * @param string $version The version in which the ability was deprecated.
+ */
+ do_action( 'deprecated_ability_run', $ability_name, $replacement, $version );
+
+ /**
+ * Filters whether to trigger an error for deprecated abilities.
+ *
+ * @since 7.0.0
+ *
+ * @param bool $trigger Whether to trigger the error for deprecated abilities. Default true.
+ */
+ if ( WP_DEBUG && apply_filters( 'deprecated_ability_trigger_error', true ) ) {
+ if ( function_exists( '__' ) ) {
+ if ( $replacement ) {
+ if ( $version ) {
+ $message = sprintf(
+ /* translators: 1: Ability name, 2: Version number, 3: Alternative ability name. */
+ __( 'Ability %1$s is deprecated since version %2$s! Use %3$s instead.' ),
+ $ability_name,
+ $version,
+ $replacement
+ );
+ } else {
+ $message = sprintf(
+ /* translators: 1: Ability name, 2: Alternative ability name. */
+ __( 'Ability %1$s is deprecated! Use %2$s instead.' ),
+ $ability_name,
+ $replacement
+ );
+ }
+ } else {
+ if ( $version ) {
+ $message = sprintf(
+ /* translators: 1: Ability name, 2: Version number. */
+ __( 'Ability %1$s is deprecated since version %2$s with no alternative available.' ),
+ $ability_name,
+ $version
+ );
+ } else {
+ $message = sprintf(
+ /* translators: %s: Ability name. */
+ __( 'Ability %s is deprecated with no alternative available.' ),
+ $ability_name
+ );
+ }
+ }
+ } else {
+ if ( $replacement ) {
+ if ( $version ) {
+ $message = sprintf(
+ 'Ability %1$s is deprecated since version %2$s! Use %3$s instead.',
+ $ability_name,
+ $version,
+ $replacement
+ );
+ } else {
+ $message = sprintf(
+ 'Ability %1$s is deprecated! Use %2$s instead.',
+ $ability_name,
+ $replacement
+ );
+ }
+ } else {
+ if ( $version ) {
+ $message = sprintf(
+ 'Ability %1$s is deprecated since version %2$s with no alternative available.',
+ $ability_name,
+ $version
+ );
+ } else {
+ $message = sprintf(
+ 'Ability %s is deprecated with no alternative available.',
+ $ability_name
+ );
+ }
+ }
+ }
+
+ wp_trigger_error( '', $message, E_USER_DEPRECATED );
+ }
+}
diff --git a/src/wp-includes/abilities-api/class-wp-ability.php b/src/wp-includes/abilities-api/class-wp-ability.php
index d116080c1ccdc..f3a1e3152d927 100644
--- a/src/wp-includes/abilities-api/class-wp-ability.php
+++ b/src/wp-includes/abilities-api/class-wp-ability.php
@@ -325,6 +325,7 @@ protected function prepare_properties( array $args ): array {
$args['meta'] ?? array(),
array(
'annotations' => static::$default_annotations,
+ 'deprecated' => false,
'show_in_rest' => self::DEFAULT_SHOW_IN_REST,
)
);
@@ -553,6 +554,13 @@ protected function do_execute( $input = null ) {
);
}
+ // Trigger deprecation notice if the ability is deprecated.
+ if ( $this->get_meta_item( 'deprecated', false ) === true ) {
+ $version = $this->get_meta_item( 'deprecated_version', '' );
+ $replacement = $this->get_meta_item( 'deprecated_replacement', '' );
+ _deprecated_ability( $this->name, $version, $replacement );
+ }
+
return $this->invoke_callback( $this->execute_callback, $input );
}