register_block(); $this->load_textdomain(); } private function register_block(): void { register_block_type(self::BLOCK_NAME, [ 'editor_script' => 'git-embed-feicode-editor', 'editor_style' => 'git-embed-feicode-style', 'style' => 'git-embed-feicode-style', 'render_callback' => [$this, 'render_block'], 'attributes' => [ 'platform' => [ 'type' => 'string', 'default' => 'github' ], 'owner' => [ 'type' => 'string', 'default' => '' ], 'repo' => [ 'type' => 'string', 'default' => '' ], 'showDescription' => [ 'type' => 'boolean', 'default' => true ], 'showStats' => [ 'type' => 'boolean', 'default' => true ], 'showLanguage' => [ 'type' => 'boolean', 'default' => true ], 'showActions' => [ 'type' => 'boolean', 'default' => true ], 'showViewButton' => [ 'type' => 'boolean', 'default' => true ], 'showCloneButton' => [ 'type' => 'boolean', 'default' => true ], 'showDownloadButton' => [ 'type' => 'boolean', 'default' => true ], 'cardStyle' => [ 'type' => 'string', 'default' => 'default' ], 'buttonStyle' => [ 'type' => 'string', 'default' => 'primary' ], 'showAvatar' => [ 'type' => 'boolean', 'default' => true ], 'showSiteInfo' => [ 'type' => 'boolean', 'default' => true ], 'avatarSize' => [ 'type' => 'string', 'default' => 'medium' ], 'alignment' => [ 'type' => 'string', 'default' => 'none' ] ] ]); wp_register_script( 'git-embed-feicode-editor', plugin_dir_url(__FILE__) . 'block.js', ['wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'], self::PLUGIN_VERSION ); wp_register_style( 'git-embed-feicode-style', plugin_dir_url(__FILE__) . 'style.css', [], self::PLUGIN_VERSION ); wp_localize_script('git-embed-feicode-editor', 'gitEmbedAjax', [ 'url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('git_embed_nonce'), 'cache_nonce' => wp_create_nonce('git_embed_cache_nonce') ]); } public function render_block(array $attributes): string { $owner = sanitize_text_field($attributes['owner'] ?? ''); $repo = sanitize_text_field($attributes['repo'] ?? ''); $platform = sanitize_text_field($attributes['platform'] ?? 'github'); if (empty($owner) || empty($repo)) { return '
'; } $repo_data = $this->fetch_repository_data($platform, $owner, $repo); if (!$repo_data) { return ' '; } return $this->render_repository_card($repo_data, $attributes); } private function fetch_repository_data(string $platform, string $owner, string $repo): ?array { if ($platform !== 'github') { return null; } $cache_key = "git_embed_{$platform}_{$owner}_{$repo}"; $cached = get_transient($cache_key); if ($cached !== false) { return $cached; } $url = "https://api.github.com/repos/{$owner}/{$repo}"; $response = wp_remote_get($url, [ 'timeout' => 15, 'headers' => [ 'User-Agent' => 'Git-Embed-FeiCode/1.0', 'Accept' => 'application/vnd.github.v3+json' ] ]); if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) { return null; } $data = json_decode(wp_remote_retrieve_body($response), true); if (!$data) { return null; } $repo_data = [ 'name' => $data['name'], 'full_name' => $data['full_name'], 'description' => $data['description'], 'html_url' => $data['html_url'], 'language' => $data['language'], 'stargazers_count' => $data['stargazers_count'], 'forks_count' => $data['forks_count'], 'open_issues_count' => $data['open_issues_count'], 'clone_url' => $data['clone_url'], 'archive_url' => $data['archive_url'], 'owner' => [ 'login' => $data['owner']['login'], 'avatar_url' => $data['owner']['avatar_url'], 'html_url' => $data['owner']['html_url'], 'type' => $data['owner']['type'] ], 'site_info' => [ 'name' => 'GitHub', 'url' => 'https://github.com', 'favicon' => 'https://github.com/favicon.ico', 'color' => '#24292f' ] ]; set_transient($cache_key, $repo_data, DAY_IN_SECONDS); $this->cache_avatar($repo_data['owner']['avatar_url']); return $repo_data; } private function cache_avatar(string $avatar_url): void { if (empty($avatar_url)) { return; } $cache_key = 'git_embed_avatar_' . md5($avatar_url); if (get_transient($cache_key) !== false) { return; } $response = wp_remote_get($avatar_url, [ 'timeout' => 10, 'headers' => [ 'User-Agent' => 'Git-Embed-FeiCode/1.0' ] ]); if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { set_transient($cache_key, true, WEEK_IN_SECONDS); } } private function render_repository_card(array $repo_data, array $attributes): string { $show_description = $attributes['showDescription'] ?? true; $show_stats = $attributes['showStats'] ?? true; $show_language = $attributes['showLanguage'] ?? true; $show_actions = $attributes['showActions'] ?? true; $show_view_button = $attributes['showViewButton'] ?? true; $show_clone_button = $attributes['showCloneButton'] ?? true; $show_download_button = $attributes['showDownloadButton'] ?? true; $show_avatar = $attributes['showAvatar'] ?? true; $show_site_info = $attributes['showSiteInfo'] ?? true; $avatar_size = $attributes['avatarSize'] ?? 'medium'; $card_style = $attributes['cardStyle'] ?? 'default'; $button_style = $attributes['buttonStyle'] ?? 'primary'; $alignment = $attributes['alignment'] ?? 'none'; $align_class = $alignment !== 'none' ? " align{$alignment}" : ''; $card_class = $card_style !== 'default' ? " git-embed-card-{$card_style}" : ''; $avatar_class = "git-embed-avatar-{$avatar_size}"; $download_url = str_replace('{archive_format}', 'zipball', $repo_data['archive_url']); $download_url = str_replace('{/ref}', '/main', $download_url); ob_start(); ?> fetch_repository_data($platform, $owner, $repo); if (!$repo_data) { wp_send_json_error('Failed to fetch repository data'); } wp_send_json_success($repo_data); } public function ajax_clear_cache(): void { check_ajax_referer('git_embed_cache_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error('Insufficient permissions'); } $platform = sanitize_text_field($_POST['platform'] ?? ''); $owner = sanitize_text_field($_POST['owner'] ?? ''); $repo = sanitize_text_field($_POST['repo'] ?? ''); if (empty($owner) || empty($repo)) { wp_send_json_error('Repository information required'); } $this->clear_repository_cache($platform, $owner, $repo); wp_send_json_success('Cache cleared successfully'); } private function clear_repository_cache(string $platform, string $owner, string $repo): void { $cache_key = "git_embed_{$platform}_{$owner}_{$repo}"; delete_transient($cache_key); global $wpdb; $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like('_transient_git_embed_avatar_') . '%' ) ); $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like('_transient_timeout_git_embed_avatar_') . '%' ) ); } public function clear_all_cache(): void { global $wpdb; $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like('_transient_git_embed_') . '%' ) ); $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s", $wpdb->esc_like('_transient_timeout_git_embed_') . '%' ) ); } private function load_textdomain(): void { load_plugin_textdomain( 'git-embed-feicode', false, dirname(plugin_basename(__FILE__)) . '/languages' ); } } new GitEmbedFeiCode();