__('Forgejo base URL', 'ansico-plugins'), 'forgejo_owner' => __('Bruger eller organisation', 'ansico-plugins'), 'access_token' => __('Access token', 'ansico-plugins'), 'topic_filter' => __('Topic-filter', 'ansico-plugins'), 'request_timeout' => __('Timeout (sekunder)', 'ansico-plugins'), ); foreach ($fields as $key => $label) { add_settings_field($key, $label, array($this, 'render_field'), 'ansico-plugins', 'ansico_plugins_connection', array('key' => $key)); } add_settings_field('owner_type', __('Owner-type', 'ansico-plugins'), array($this, 'render_owner_type_field'), 'ansico-plugins', 'ansico_plugins_connection'); add_settings_field('verify_ssl', __('SSL-verifikation', 'ansico-plugins'), array($this, 'render_verify_ssl_field'), 'ansico-plugins', 'ansico_plugins_connection'); add_settings_section( 'ansico_plugins_self_update', __('Opdatering af Ansico Plugins', 'ansico-plugins'), '__return_false', 'ansico-plugins' ); add_settings_field('self_update_enabled', __('Slå selvopdatering til', 'ansico-plugins'), array($this, 'render_self_update_enabled_field'), 'ansico-plugins', 'ansico_plugins_self_update'); add_settings_field('self_update_owner', __('Ansico plugins owner', 'ansico-plugins'), array($this, 'render_field'), 'ansico-plugins', 'ansico_plugins_self_update', array('key' => 'self_update_owner')); add_settings_field('self_update_repo', __('Ansico plugins repository', 'ansico-plugins'), array($this, 'render_field'), 'ansico-plugins', 'ansico_plugins_self_update', array('key' => 'self_update_repo')); } public function sanitize_settings($input) { $output = Ansico_Plugins::get_settings(); $output['forgejo_base_url'] = isset($input['forgejo_base_url']) ? esc_url_raw(trim((string) $input['forgejo_base_url'])) : ''; $output['forgejo_owner'] = isset($input['forgejo_owner']) ? sanitize_text_field($input['forgejo_owner']) : ''; $output['owner_type'] = isset($input['owner_type']) && in_array($input['owner_type'], array('user', 'org'), true) ? $input['owner_type'] : 'org'; $output['access_token'] = isset($input['access_token']) ? sanitize_text_field($input['access_token']) : ''; $output['topic_filter'] = isset($input['topic_filter']) ? sanitize_text_field($input['topic_filter']) : 'wordpress-plugin'; $output['verify_ssl'] = !empty($input['verify_ssl']) ? 1 : 0; $output['request_timeout'] = isset($input['request_timeout']) ? max(5, (int) $input['request_timeout']) : 20; $output['self_update_enabled'] = !empty($input['self_update_enabled']) ? 1 : 0; $output['self_update_owner'] = isset($input['self_update_owner']) ? sanitize_text_field($input['self_update_owner']) : ''; $output['self_update_repo'] = isset($input['self_update_repo']) ? sanitize_text_field($input['self_update_repo']) : ''; Ansico_Plugins::clear_http_cache(); wp_clean_plugins_cache(true); delete_site_transient('update_plugins'); return $output; } public function maybe_handle_reset_defaults() { if (!is_admin() || !current_user_can('manage_options') || empty($_GET['ansico_reset_defaults'])) { return; } if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'ansico_plugins_reset_defaults')) { return; } update_option(ANSICO_PLUGINS_OPTION, Ansico_Plugins::default_settings(), false); Ansico_Plugins::clear_http_cache(); wp_clean_plugins_cache(true); delete_site_transient('update_plugins'); wp_safe_redirect(admin_url('options-general.php?page=ansico-plugins&ansico_reset_done=1')); exit; } public function maybe_show_reset_notice() { if (!current_user_can('manage_options') || empty($_GET['ansico_reset_done'])) { return; } echo '

' . esc_html__('Ansico standardindstillinger er gendannet.', 'ansico-plugins') . '

'; } public function render_field($args) { $settings = Ansico_Plugins::get_settings(); $key = $args['key']; $value = isset($settings[$key]) ? $settings[$key] : ''; $type = 'text'; if ('access_token' === $key) { $type = 'password'; } elseif ('request_timeout' === $key) { $type = 'number'; } elseif ('forgejo_base_url' === $key) { $type = 'url'; } printf( '', esc_attr($type), esc_attr(ANSICO_PLUGINS_OPTION), esc_attr($key), esc_attr($value), 'request_timeout' === $key ? 'min="5" step="1"' : '' ); $help = array( 'forgejo_base_url' => __('Eksempel: https://forgejo.ditdomæne.dk/', 'ansico-plugins'), 'forgejo_owner' => __('Navn på bruger eller organisation som ejer repositories.', 'ansico-plugins'), 'access_token' => __('PAT med adgang til at læse repos/releases. Kræves ofte for private repos.', 'ansico-plugins'), 'topic_filter' => __('Kun repos med dette topic vises. Brug tomt felt for at vise alle repos.', 'ansico-plugins'), 'request_timeout' => __('Øg værdien hvis Forgejo-serveren er langsom.', 'ansico-plugins'), 'self_update_owner' => __('Organisation eller bruger som ejer Ansico Plugins-repository.', 'ansico-plugins'), 'self_update_repo' => __('Repository-navn for Ansico Plugins, fx Ansico-plugins.', 'ansico-plugins'), ); if (isset($help[$key])) { echo '

' . esc_html($help[$key]) . '

'; } } public function render_owner_type_field() { $settings = Ansico_Plugins::get_settings(); ?>

' . esc_html__('Reset til Ansico standard', 'ansico-plugins') . ''; ?>


test_connection(); if (is_wp_error($result)) { printf( '

%s %s

', esc_html__('Forgejo-forbindelse fejlede:', 'ansico-plugins'), esc_html($result->get_error_message()) ); return; } printf( '

%s %s

', esc_html__('Forbindelse OK. Forgejo-version:', 'ansico-plugins'), esc_html($result['version']) ); } public function render_catalog_page() { if (!current_user_can('install_plugins')) { return; } $client = new Ansico_Plugins_Client(); $repos = $client->get_repositories(); if (isset($_GET['ansico_view']) && 'details' === sanitize_key(wp_unslash($_GET['ansico_view']))) { $this->render_details_page($client, $repos, false); return; } $settings = Ansico_Plugins::get_settings(); $owner_label = !empty($settings['forgejo_owner']) ? $settings['forgejo_owner'] : __('din organisation', 'ansico-plugins'); $forgejo_link = !empty($settings['forgejo_base_url']) ? trailingslashit($settings['forgejo_base_url']) . rawurlencode($owner_label) : ''; ?>
render_catalog_styles(); ?>


%2$s.', 'ansico-plugins'), array('a' => array('href' => array(), 'target' => array(), 'rel' => array())) ), esc_url($forgejo_link), esc_html($owner_label) ); ?>

get_self_plugin_status_markup($client); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>

%s

', esc_html($repos->get_error_message())); echo '

' . esc_html__('Gå til indstillinger', 'ansico-plugins') . '

'; echo ''; return; } if (empty($repos)) { echo '

' . esc_html__('Ingen repositories matchede de valgte kriterier.', 'ansico-plugins') . '

'; echo '

' . esc_html__('Forgejo svarer, men ingen repos matchede topic-filteret. Kontrollér topic-navn og gem indstillingerne igen for at rydde cache.', 'ansico-plugins') . '

'; echo ''; return; } if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $installed_plugins = get_plugins(); $managed_plugins = Ansico_Plugins::get_managed_plugins(); echo '
'; foreach ($repos as $repo) { $release = $client->get_latest_release($repo['owner']['login'], $repo['name']); $zip_asset = !is_wp_error($release) ? $client->find_zip_asset($release) : null; $plugin_state = $this->get_plugin_state($repo, $installed_plugins, $managed_plugins, $release); $metadata = $client->get_repository_plugin_metadata($repo['owner']['login'], $repo['name']); $metadata = is_wp_error($metadata) ? array() : $metadata; $display_name = !empty($metadata['readme_title']) ? $metadata['readme_title'] : $repo['name']; $details_url = $this->get_details_url($repo['name']); $badge = $this->get_state_badge($plugin_state); $version_label = is_wp_error($release) ? '—' : $this->normalize_release_version($release); echo '
'; echo '
'; echo '
AP
'; echo '
'; echo '

' . esc_html($display_name) . '

'; echo '
' . $badge . '
'; echo '
'; echo '

' . esc_html(!empty($repo['description']) ? $repo['description'] : __('Ingen beskrivelse angivet.', 'ansico-plugins')) . '

'; echo '
'; echo '' . esc_html__('Installeret', 'ansico-plugins') . ': ' . esc_html($plugin_state['installed_version'] !== '' ? $plugin_state['installed_version'] : '—') . ''; echo '' . esc_html__('Seneste', 'ansico-plugins') . ': ' . esc_html($version_label) . ''; echo '
'; echo '
'; foreach ($this->build_action_buttons($repo, $plugin_state, $zip_asset) as $button_html) { echo $button_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } echo '' . esc_html__('Vis detaljer', 'ansico-plugins') . ''; echo '
'; echo $this->get_details_inline_markup($repo, $release, $zip_asset, $plugin_state, $metadata); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo '
'; } echo '
'; } private function render_details_page($client, $repos, $is_modal = false) { $repo_name = isset($_GET['repo']) ? sanitize_text_field(wp_unslash($_GET['repo'])) : ''; $repo = null; if (!is_wp_error($repos)) { foreach ($repos as $candidate) { if (!empty($candidate['name']) && $candidate['name'] === $repo_name) { $repo = $candidate; break; } } } if (!$repo) { wp_die(esc_html__('Repository blev ikke fundet.', 'ansico-plugins')); } if (!function_exists('get_plugins')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $installed_plugins = get_plugins(); $managed_plugins = Ansico_Plugins::get_managed_plugins(); $release = $client->get_latest_release($repo['owner']['login'], $repo['name']); $zip_asset = !is_wp_error($release) ? $client->find_zip_asset($release) : null; $plugin_state = $this->get_plugin_state($repo, $installed_plugins, $managed_plugins, $release); $metadata = $client->get_repository_plugin_metadata($repo['owner']['login'], $repo['name']); $metadata = is_wp_error($metadata) ? array() : $metadata; $back_url = admin_url('plugins.php?page=ansico-plugins-catalog'); echo '
'; $this->render_catalog_styles(); echo '

' . esc_html(!empty($metadata['readme_title']) ? $metadata['readme_title'] : $repo['name']) . '

'; echo '' . esc_html__('Tilbage til katalog', 'ansico-plugins') . ''; echo '
'; echo $this->get_details_content_markup($repo, $release, $zip_asset, $plugin_state, $metadata); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo '
'; exit; } private function build_action_buttons($repo, $plugin_state, $zip_asset) { $buttons = array(); $repo_name = $repo['name']; $slug = $repo['name']; if (!$plugin_state['is_installed'] && $zip_asset) { $buttons[] = '' . esc_html__('Installér', 'ansico-plugins') . ''; return $buttons; } if ($plugin_state['is_installed'] && !$plugin_state['is_active']) { $buttons[] = '' . esc_html__('Aktivér', 'ansico-plugins') . ''; $buttons[] = '' . esc_html__('Afinstallér', 'ansico-plugins') . ''; return $buttons; } if ($plugin_state['is_installed'] && $plugin_state['has_update']) { $buttons[] = '' . esc_html__('Opdatér', 'ansico-plugins') . ''; $buttons[] = '' . esc_html__('Afinstallér', 'ansico-plugins') . ''; return $buttons; } if ($plugin_state['is_installed'] && $plugin_state['is_active']) { $buttons[] = '' . esc_html__('Geninstallér', 'ansico-plugins') . ''; $buttons[] = '' . esc_html__('Afinstallér', 'ansico-plugins') . ''; } return $buttons; } private function get_plugin_state($repo, $installed_plugins, $managed_plugins, $release) { $plugin_file = ''; foreach ($managed_plugins as $candidate_plugin_file => $meta) { if (!empty($meta['owner']) && !empty($meta['repo']) && $meta['owner'] === $repo['owner']['login'] && $meta['repo'] === $repo['name']) { $plugin_file = $candidate_plugin_file; break; } } if ('' === $plugin_file) { foreach ($installed_plugins as $candidate_plugin_file => $plugin_data) { if (dirname($candidate_plugin_file) === sanitize_title($repo['name'])) { $plugin_file = $candidate_plugin_file; break; } } } $is_installed = '' !== $plugin_file && isset($installed_plugins[$plugin_file]); $installed_version = $is_installed && !empty($installed_plugins[$plugin_file]['Version']) ? (string) $installed_plugins[$plugin_file]['Version'] : ''; $is_active = $is_installed ? is_plugin_active($plugin_file) : false; $remote_version = !is_wp_error($release) ? $this->normalize_release_version($release) : ''; $has_update = $is_installed && '' !== $installed_version && '' !== $remote_version && version_compare($remote_version, $installed_version, '>'); return array( 'plugin_file' => $plugin_file, 'is_installed' => $is_installed, 'is_active' => $is_active, 'installed_version' => $installed_version, 'remote_version' => $remote_version, 'has_update' => $has_update, ); } private function normalize_release_version($release) { $version = ''; if (!empty($release['tag_name'])) { $version = (string) $release['tag_name']; } elseif (!empty($release['name'])) { $version = (string) $release['name']; } $version = ltrim($version, 'vV'); return '' !== $version ? $version : '—'; } private function get_state_badge($plugin_state) { if (!$plugin_state['is_installed']) { if (empty($plugin_state['remote_version']) || '—' === $plugin_state['remote_version']) { return '' . esc_html__('Ikke udgivet', 'ansico-plugins') . ''; } return '' . esc_html__('Ikke installeret', 'ansico-plugins') . ''; } if ($plugin_state['has_update']) { return '' . esc_html__('Opdatering klar', 'ansico-plugins') . ''; } if (!$plugin_state['is_active']) { return '' . esc_html__('Installeret', 'ansico-plugins') . ''; } return '' . esc_html__('Aktiv', 'ansico-plugins') . ''; } private function get_self_plugin_status_markup($client) { $settings = Ansico_Plugins::get_settings(); if (empty($settings['self_update_enabled']) || empty($settings['self_update_owner']) || empty($settings['self_update_repo'])) { return ''; } if (!function_exists('get_plugin_data')) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $plugin_file = plugin_basename(ANSICO_PLUGINS_FILE); $plugin_data = get_plugin_data(ANSICO_PLUGINS_FILE, false, false); $current_version = !empty($plugin_data['Version']) ? (string) $plugin_data['Version'] : ANSICO_PLUGINS_VERSION; $release = $client->get_latest_release($settings['self_update_owner'], $settings['self_update_repo']); if (is_wp_error($release)) { return '

' . esc_html__('Ansico Plugins: kunne ikke hente opdateringsstatus.', 'ansico-plugins') . '

'; } $remote_version = $this->normalize_release_version($release); $repo_url = trailingslashit($settings['forgejo_base_url']) . rawurlencode($settings['self_update_owner']) . '/' . rawurlencode($settings['self_update_repo']); if ('' === $remote_version || '—' === $remote_version) { return '

' . esc_html__('Ansico Plugins: ingen udgivet version fundet endnu.', 'ansico-plugins') . '

'; } if (version_compare($remote_version, $current_version, '>')) { $update_url = esc_url(admin_url('plugins.php')); return '

' . sprintf( wp_kses( __('Ansico Plugins: version %1$s er installeret, og version %2$s er tilgængelig fra %4$s. Opdater fra den almindelige Plugins-side.', 'ansico-plugins'), array('a' => array('href' => array(), 'target' => array(), 'rel' => array())) ), esc_html($current_version), esc_html($remote_version), esc_url($repo_url), esc_html($settings['self_update_repo']), esc_url($update_url) ) . '

'; } return '

' . sprintf( wp_kses( __('Ansico Plugins er opdateret. Installeret version %1$s matcher seneste release i %3$s.', 'ansico-plugins'), array('a' => array('href' => array(), 'target' => array(), 'rel' => array())) ), esc_html($current_version), esc_url($repo_url), esc_html($settings['self_update_repo']) ) . '

'; } private function get_details_url($repo_name) { return '#TB_inline?width=920&height=648&inlineId=ansico-plugin-details-' . rawurlencode(sanitize_title($repo_name)); } private function build_action_url($action, $repo_name, $slug, $plugin_file = '') { $url = admin_url('plugins.php?page=ansico-plugins-catalog&ansico_action=' . rawurlencode($action) . '&repo=' . rawurlencode($repo_name) . '&slug=' . rawurlencode($slug)); if ('' !== $plugin_file) { $url .= '&plugin_file=' . rawurlencode($plugin_file); } return wp_nonce_url($url, 'ansico_plugins_action'); } private function get_details_inline_markup($repo, $release, $zip_asset, $plugin_state, $metadata) { $id = 'ansico-plugin-details-' . sanitize_title($repo['name']); return ''; } private function get_details_content_markup($repo, $release, $zip_asset, $plugin_state, $metadata) { $display_name = !empty($metadata['readme_title']) ? $metadata['readme_title'] : $repo['name']; $html = ''; $html .= '
'; $html .= '
AP
'; $html .= '
'; $html .= '

' . esc_html($display_name) . '

'; $html .= '

' . esc_html(!empty($repo['description']) ? $repo['description'] : __('Ingen beskrivelse angivet.', 'ansico-plugins')) . '

'; $html .= $this->get_state_badge($plugin_state); $html .= '
'; $html .= '
'; foreach ($this->build_action_buttons($repo, $plugin_state, $zip_asset) as $button_html) { $html .= $button_html; } $html .= '' . esc_html__('Åbn repository', 'ansico-plugins') . ''; $html .= '
'; $html .= '
'; $meta_rows = array( __('Installeret version', 'ansico-plugins') => $plugin_state['installed_version'] !== '' ? $plugin_state['installed_version'] : '—', __('Seneste release', 'ansico-plugins') => !is_wp_error($release) ? $this->normalize_release_version($release) : '—', __('Repository', 'ansico-plugins') => !empty($repo['full_name']) ? $repo['full_name'] : $repo['name'], __('ZIP-fil', 'ansico-plugins') => $zip_asset && !empty($zip_asset['name']) ? $zip_asset['name'] : '—', __('Forfatter', 'ansico-plugins') => !empty($metadata['author_name']) ? $metadata['author_name'] : '—', __('Forfatter-URL', 'ansico-plugins') => !empty($metadata['author_url']) ? $metadata['author_url'] : '—', __('Support-URL', 'ansico-plugins') => !empty($metadata['support_url']) ? $metadata['support_url'] : '—', __('Licens', 'ansico-plugins') => !empty($metadata['license']) ? $metadata['license'] : '—', __('Plugin-URL', 'ansico-plugins') => !empty($metadata['plugin_headers']['PluginURI']) ? $metadata['plugin_headers']['PluginURI'] : '—', __('Kræver WordPress', 'ansico-plugins') => !empty($metadata['plugin_headers']['RequiresWP']) ? $metadata['plugin_headers']['RequiresWP'] : '—', __('Kræver PHP', 'ansico-plugins') => !empty($metadata['plugin_headers']['RequiresPHP']) ? $metadata['plugin_headers']['RequiresPHP'] : '—', __('Text domain', 'ansico-plugins') => !empty($metadata['plugin_headers']['TextDomain']) ? $metadata['plugin_headers']['TextDomain'] : '—', ); foreach ($meta_rows as $label => $value) { $html .= '

' . esc_html($label) . '
'; if (is_string($value) && preg_match('#^https?://#i', $value)) { $html .= '' . esc_html($value) . ''; } else { $html .= esc_html($value); } $html .= '

'; } $html .= '
'; if (!empty($metadata['screenshot_url'])) { $html .= '
'; $html .= '

' . esc_html__('Screenshot', 'ansico-plugins') . '

'; $html .= '' . esc_attr(sprintf(__('Screenshot for %s', 'ansico-plugins'), $display_name)) . ''; $html .= '
'; } if (!is_wp_error($release) && !empty($release['body'])) { $html .= '

' . esc_html__('Release-noter', 'ansico-plugins') . '

'; $html .= '
' . wp_kses_post(wpautop($release['body'])) . '
'; } return $html; } private function render_catalog_styles() { echo ''; } }