sanitize_text_field( $minimum_core ), 'requires_api' => sanitize_text_field( $minimum_api ) ];
return false;
}
$capabilities = isset( $metadata['capabilities'] ) && is_array( $metadata['capabilities'] )
? array_values( array_unique( array_filter( array_map( 'sanitize_key', $metadata['capabilities'] ) ) ) ) : [];
self::$extensions[ $normalized_id ] = [
'id' => $normalized_id, 'label' => sanitize_text_field( $metadata['label'] ?? $normalized_id ),
'version' => sanitize_text_field( $metadata['version'] ?? '' ), 'requires_core' => $minimum_core,
'requires_api' => $minimum_api, 'capabilities' => $capabilities,
];
unset( self::$compatibility_failures[ $normalized_id ] );
do_action( 'nyxonn_fx_extension_registered', $normalized_id, self::$extensions[ $normalized_id ] );
return true;
}
public static function get_extension( $id ) {
$id = self::valid_id( $id );
return $id && isset( self::$extensions[ $id ] ) ? self::$extensions[ $id ] : null;
}
public static function get_extensions() { return self::$extensions; }
public static function has_extension( $id ) { return null !== self::get_extension( $id ); }
/** Store a pre-registered handle for loading exclusively on Builder routes. */
public static function register_builder_asset( $handle, $metadata = [] ) {
$handle = self::valid_id( $handle );
$kind = sanitize_key( $metadata['kind'] ?? 'script' );
$owner = self::valid_id( $metadata['owner'] ?? 'extension' );
if ( ! $handle || ! $owner || ! in_array( $kind, [ 'script', 'style' ], true ) || isset( self::$builder_assets[ $kind . ':' . $handle ] ) ) return false;
self::$builder_assets[ $kind . ':' . $handle ] = [ 'handle' => $handle, 'kind' => $kind, 'owner' => $owner ];
return true;
}
public static function get_builder_assets( $kind = '' ) {
$kind = sanitize_key( $kind );
return array_values( array_filter( self::$builder_assets, static function ( $asset ) use ( $kind ) { return ! $kind || $kind === $asset['kind']; } ) );
}
/** Register a routed internal-admin item; a callable prevents blank routes. */
public static function register_admin_navigation( $item ) {
if ( ! is_array( $item ) ) return false;
$slug = self::valid_id( $item['slug'] ?? '' );
$label = sanitize_text_field( $item['label'] ?? '' );
$capability = sanitize_key( $item['capability'] ?? 'manage_options' );
$callback = $item['callback'] ?? null;
$core_routes = [ 'nyxonn-builder-pages', 'nyxonn-builder-builder-settings', 'nyxonn-builder-theme-builder', 'nyxonn-builder-global-design', 'nyxonn-builder-assets', 'nyxonn-builder-role-manager', 'nyxonn-builder-performance', 'nyxonn-builder-integrations', 'nyxonn-builder-tools', 'nyxonn-builder-settings', 'nyxonn-builder-upgrade-pro', 'nyxonn-builder-editor', 'nyxonn-builder-template-conditions', 'nyxonn-builder-templates' ];
if ( ! $slug || 0 !== strpos( $slug, 'nx_' ) || in_array( $slug, $core_routes, true ) || ! $label || ! $capability || ! is_callable( $callback ) || isset( self::$admin_navigation[ $slug ] ) ) return false;
self::$admin_navigation[ $slug ] = [
'slug' => $slug, 'label' => $label, 'page_title' => sanitize_text_field( $item['page_title'] ?? $label ),
'section' => sanitize_text_field( $item['section'] ?? '' ), 'icon' => sanitize_html_class( $item['icon'] ?? 'dashicons-admin-generic' ),
'order' => is_numeric( $item['order'] ?? null ) ? (float) $item['order'] : 999, 'capability' => $capability,
'callback' => $callback, 'owner' => self::valid_id( $item['owner'] ?? 'extension' ) ?: 'extension',
];
return true;
}
public static function get_admin_navigation() { return array_values( self::$admin_navigation ); }
public static function get_compatibility_failures() { return self::$compatibility_failures; }
public static function render_compatibility_notices() {
if ( ! current_user_can( 'activate_plugins' ) ) return;
foreach ( self::$compatibility_failures as $id => $requirements ) {
printf(
'
',
esc_html( sprintf( /* translators: 1: extension ID, 2: required core version, 3: required Extension API version. */ __( 'Nyxonn extension "%1$s" was not loaded because it requires core %2$s and Extension API %3$s.', 'nyxonn-builder' ), $id, $requirements['requires_core'] ?: __( 'any', 'nyxonn-builder' ), $requirements['requires_api'] ?: __( 'any', 'nyxonn-builder' ) ) )
);
}
}
private static function valid_id( $value ) {
$value = is_string( $value ) ? trim( $value ) : '';
return $value && strlen( $value ) <= 100 && sanitize_key( $value ) === $value && preg_match( '/^[a-z][a-z0-9_-]*$/', $value ) ? $value : '';
}
private static function valid_version_requirement( $version ) {
return '' === (string) $version || ( strlen( (string) $version ) <= 32 && (bool) preg_match( '/^[0-9]+(?:\.[0-9]+){0,3}(?:[-+][A-Za-z0-9.-]+)?$/', (string) $version ) );
}
}
}
namespace {
function nyxonn_fx_get_core_version() { return defined( 'NYXONN_BUILDER_VERSION' ) ? NYXONN_BUILDER_VERSION : ''; }
function nyxonn_fx_get_extension_api_version() { return \NyxonnBuilder\Extension_API::API_VERSION; }
function nyxonn_fx_get_capabilities() { return \NyxonnBuilder\Extension_API::get_capabilities(); }
function nyxonn_fx_is_core_loaded() { return \NyxonnBuilder\Extension_API::is_core_loaded(); }
function nyxonn_fx_core_supports( $capability ) { return \NyxonnBuilder\Extension_API::core_supports( $capability ); }
function nyxonn_fx_is_extension_compatible( $minimum_core = '', $minimum_api = '' ) { return \NyxonnBuilder\Extension_API::is_compatible( $minimum_core, $minimum_api ); }
function nyxonn_fx_register_extension( $id, $metadata = [] ) { return \NyxonnBuilder\Extension_API::register_extension( $id, $metadata ); }
function nyxonn_fx_get_extension( $id ) { return \NyxonnBuilder\Extension_API::get_extension( $id ); }
function nyxonn_fx_get_extensions() { return \NyxonnBuilder\Extension_API::get_extensions(); }
function nyxonn_fx_has_extension( $id ) { return \NyxonnBuilder\Extension_API::has_extension( $id ); }
function nyxonn_fx_register_module( $definition ) { return class_exists( '\NyxonnBuilder\Module_Registry' ) && \NyxonnBuilder\Module_Registry::register_module( $definition ); }
function nyxonn_fx_register_module_renderer( $type, $renderer, $metadata = [] ) { return class_exists( '\NyxonnBuilder\Module_Registry' ) && \NyxonnBuilder\Module_Registry::register_renderer( $type, $renderer, $metadata ); }
function nyxonn_fx_register_dynamic_provider( $id, $metadata = [] ) { return class_exists( '\NyxonnBuilder\Dynamic_Content' ) && \NyxonnBuilder\Dynamic_Content::register_provider( $id, $metadata ); }
function nyxonn_fx_register_dynamic_source( $provider, $id, $metadata, $resolver ) { return class_exists( '\NyxonnBuilder\Dynamic_Content' ) && \NyxonnBuilder\Dynamic_Content::register_source( $provider, $id, $metadata, $resolver ); }
function nyxonn_fx_register_theme_condition( $id, $definition ) { return class_exists( '\NyxonnBuilder\Theme_Conditions' ) && \NyxonnBuilder\Theme_Conditions::register( $id, $definition ); }
function nyxonn_fx_register_builder_asset( $handle, $metadata = [] ) { return \NyxonnBuilder\Extension_API::register_builder_asset( $handle, $metadata ); }
function nyxonn_fx_register_admin_navigation( $item ) { return \NyxonnBuilder\Extension_API::register_admin_navigation( $item ); }
function nyxonn_fx_register_feature( $id, $definition ) { return class_exists( '\NyxonnBuilder\Feature_Registry' ) && \NyxonnBuilder\Feature_Registry::register( $id, $definition ); }
function nyxonn_fx_get_feature( $id ) { return class_exists( '\NyxonnBuilder\Feature_Registry' ) ? \NyxonnBuilder\Feature_Registry::get( $id ) : null; }
function nyxonn_fx_is_feature_available( $id ) { return class_exists( '\NyxonnBuilder\Feature_Registry' ) && \NyxonnBuilder\Feature_Registry::is_available( $id ); }
function nyxonn_fx_is_safe_mode() { return class_exists( '\NyxonnBuilder\Safe_Mode' ) && \NyxonnBuilder\Safe_Mode::is_enabled(); }
}