$component ) { wp_register_script( self::script_handle( $tag ), plugins_url( 'assets/components/' . $component['file'], __FILE__ ), array(), self::asset_version( 'components/' . $component['file'] ), true ); $editor_dependencies[] = self::script_handle( $tag ); } wp_register_script( 'developer-embeds-editor', plugins_url( 'assets/js/editor.js', __FILE__ ), $editor_dependencies, self::asset_version( 'js/editor.js' ), true ); wp_set_script_translations( 'developer-embeds-editor', 'developer-embeds' ); wp_register_style( 'developer-embeds', plugins_url( 'assets/css/developer-embeds.css', __FILE__ ), array(), self::asset_version( 'css/developer-embeds.css' ) ); $blocks = array(); foreach ( self::components() as $tag => $component ) { $blocks[] = array( 'name' => self::block_name( $tag ), 'tag' => $tag, 'title' => $component['title'], 'description' => $component['description'], 'icon' => $component['icon'], 'keywords' => $component['keywords'], 'attributes' => $component['attributes'], 'fields' => $component['fields'], ); } wp_localize_script( 'developer-embeds-editor', 'developerEmbeds', array( 'blocks' => $blocks ) ); } /** * Registers the blocks, preferring block.json metadata when available. * * @return void */ public static function register_blocks() { foreach ( self::components() as $tag => $component ) { $block_directory = __DIR__ . '/blocks/' . $tag; if ( file_exists( $block_directory . '/block.json' ) ) { register_block_type( $block_directory, array( 'render_callback' => array( __CLASS__, 'render_block' ), ) ); continue; } register_block_type( self::block_name( $tag ), array( 'api_version' => 3, 'title' => $component['title'], 'description' => $component['description'], 'category' => 'embed', 'icon' => $component['icon'], 'keywords' => $component['keywords'], 'attributes' => $component['attributes'], 'supports' => array( 'html' => false ), 'textdomain' => 'developer-embeds', 'editor_script' => 'developer-embeds-editor', 'editor_style' => 'developer-embeds', 'render_callback' => array( __CLASS__, 'render_block' ), ) ); } } /** * Registers the shortcodes. * * @return void */ public static function register_shortcodes() { foreach ( array_keys( self::components() ) as $tag ) { add_shortcode( $tag, array( __CLASS__, 'render_shortcode' ) ); } } /** * Enqueues the front-end stylesheet. * * The stylesheet is small and applies to any page that may contain an * embed, including shortcode-only pages and widgets. The component * scripts are loaded only when an embed is rendered. * * @return void */ public static function enqueue_style() { wp_enqueue_style( 'developer-embeds' ); } /** * Enqueues the component scripts in the block editor. * * The block editor iframe needs the component scripts inside the iframe, * not just in the parent editor window. Assets enqueued on * enqueue_block_assets are included in the iframed editor as of WordPress 6.3. * * @return void */ public static function enqueue_editor_assets() { if ( ! is_admin() ) { return; } wp_enqueue_style( 'developer-embeds' ); foreach ( array_keys( self::components() ) as $tag ) { wp_enqueue_script( self::script_handle( $tag ) ); } } /** * Adds suggested privacy policy content. * * @return void */ public static function add_privacy_policy_content() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } $content = '
' . __( 'Developer Embeds displays public package and repository data. When an embed is displayed on the front end, or previewed in the editor, the browser requests data from the npm registry and downloads API, PyPI, Shields.io, and the selected repository forge. Tangled lookups may also contact api.tangled.org and public.api.bsky.app; GitHub repository preview images may be loaded from opengraph.githubassets.com. If a custom host or API URL is configured, the browser contacts that host. These services may receive the browser\'s IP address and the requested package or repository name. The plugin itself does not collect, store, or share personal data, and does not set cookies or use analytics. API responses are cached in the browser\'s sessionStorage for 15 minutes.', 'developer-embeds' ) . '
'; $content .= '' . __( 'Privacy policies and terms:', 'developer-embeds' ) . ' '; $content .= 'npm, '; $content .= 'PyPI, '; $content .= 'Python Software Foundation, '; $content .= 'Shields.io, '; $content .= 'GitHub, '; $content .= 'GitLab, '; $content .= 'Bitbucket/Atlassian, '; $content .= 'Tangled, '; $content .= 'Bluesky, '; $content .= 'SourceHut, '; $content .= 'Codeberg, '; $content .= 'Azure DevOps.'; $content .= '
'; wp_add_privacy_policy_content( 'Developer Embeds', wp_kses_post( $content ) ); } /** * Renders a block on the front end. * * @param array $attributes Block attributes. * @param string $content Block content. * @param WP_Block $block Block instance. * @return string */ public static function render_block( $attributes, $content, $block ) { $tag = str_replace( 'developer-embeds/', '', $block->name ); $component = self::components()[ $tag ] ?? null; if ( ! $component ) { return ''; } $embed = self::render_embed( $tag, $attributes, $component ); return '' === $embed ? '' : '