$sources Array of source objects from the vulnerability API. * @return string HTML div.wpvuln-source-pills, or empty string if no sources. */ function wpvulnerability_render_source_pills( $sources ) { if ( empty( $sources ) ) { return ''; } $pills = array(); foreach ( $sources as $src ) { if ( ! is_array( $src ) ) { continue; } $link = is_scalar( $src['link'] ?? '' ) ? (string) ( $src['link'] ?? '' ) : ''; // Derive label and CSS slug from the URL hostname; fall back to name/id. $label = ''; $slug_input = ''; if ( '' !== $link ) { $parsed = wp_parse_url( $link ); $host = ( is_array( $parsed ) && isset( $parsed['host'] ) ) ? (string) $parsed['host'] : ''; if ( 0 === strpos( $host, 'www.' ) ) { $host = substr( $host, 4 ); } if ( '' !== $host ) { $label = $host; $slug_input = $host; } } if ( '' === $label ) { $name = is_scalar( $src['name'] ?? '' ) ? (string) ( $src['name'] ?? '' ) : ''; if ( '' === $name ) { $name = is_scalar( $src['id'] ?? '' ) ? (string) ( $src['id'] ?? '' ) : ''; } $label = $name; $slug_input = $name; } if ( '' === $label ) { continue; } $slug = wpvulnerability_source_css_slug( $slug_input ); $cls = esc_attr( 'wpvuln-source-pill wpvuln-source-' . $slug ); $inner = esc_html( $label ); if ( '' !== $link ) { $pills[] = '' . $inner . ''; } else { $pills[] = '' . $inner . ''; } } if ( empty( $pills ) ) { return ''; } return '
' . implode( '', $pills ) . '
'; } /** * Build a colour-coded CVSS score + severity badge, optionally followed by an EPSS badge. * * @since 5.0.0 * * @param string|null $score Formatted CVSS score (e.g. "7.5") or null. * @param string|null $sev_raw Raw severity string (single-char or full word) or null. * @param float|null $epss EPSS exploitation probability 0–1, or null if not available. * @return string HTML span(s) for score and/or EPSS, or empty string if no data. */ function wpvulnerability_render_score_badge( $score, $sev_raw, $epss = null ) { if ( is_null( $score ) && ( is_null( $sev_raw ) || '' === $sev_raw ) && is_null( $epss ) ) { return ''; } $sev_lower = is_string( $sev_raw ) ? strtolower( trim( $sev_raw ) ) : ''; $css_map = array( 'c' => 'critical', 'critical' => 'critical', 'h' => 'high', 'high' => 'high', 'm' => 'medium', 'medium' => 'medium', 'l' => 'low', 'low' => 'low', 'n' => 'none', 'none' => 'none', ); $css_key = isset( $css_map[ $sev_lower ] ) ? $css_map[ $sev_lower ] : 'none'; $sev_label = ( is_string( $sev_raw ) && '' !== $sev_raw ) ? wpvulnerability_severity( $sev_raw ) : null; $parts = array(); if ( ! is_null( $score ) ) { $parts[] = esc_html( $score ); } if ( ! is_null( $sev_label ) ) { $parts[] = esc_html( $sev_label ); } $badge = ''; if ( ! empty( $parts ) ) { $badge = '' . implode( ' · ', $parts ) . ''; } if ( null !== $epss ) { $badge .= 'EPSS ' . esc_html( number_format( $epss * 100, 1 ) ) . '%'; } return $badge; } /** * Extract the best available description from a vulnerability's source array. * * Iterates source objects and returns the first non-empty description string, * stripping any leading language tag (e.g. "[en-US] ") added by the CVE API. * * @since 5.0.0 * * @param array $sources Source objects from the vulnerability API. * @return string|null First non-empty description found, or null if none. */ function wpvulnerability_get_source_description( $sources ) { if ( empty( $sources ) ) { return null; } foreach ( $sources as $src ) { if ( ! is_array( $src ) ) { continue; } $raw = isset( $src['description'] ) && is_string( $src['description'] ) ? trim( $src['description'] ) : ''; if ( '' === $raw ) { continue; } // Strip leading language tag like "[en-US] " or "[ja] ". if ( '[' === $raw[0] ) { $close = strpos( $raw, '] ' ); if ( false !== $close ) { $raw = substr( $raw, $close + 2 ); } } if ( '' !== $raw ) { return $raw; } } return null; } /** * Clean a raw API version range string for display. * * Examples: * "* - < 1.0.0" → "< 1.0.0" * "- - < 1.0.0" → "< 1.0.0" * "- < 1.0.0" → "< 1.0.0" (no space-dash-space separator) * "1.0.0 - < 2.0" → "≥ 1.0.0 – < 2.0" * * @since 5.0.0 * * @param string $versions Raw versions string from the API. * @return string Cleaned version range for display (HTML-safe). */ function wpvulnerability_clean_version_range( $versions ) { $v = trim( (string) $versions ); if ( '' === $v ) { return ''; } // Handle "- < 1.0" / "* < 1.0": leading wildcard without a space-dash-space separator. if ( 0 === strpos( $v, '- ' ) || 0 === strpos( $v, '* ' ) ) { return esc_html( ltrim( substr( $v, 2 ) ) ); } $parts = explode( ' - ', $v, 2 ); if ( 2 === count( $parts ) ) { $from = trim( $parts[0] ); $to = trim( $parts[1] ); if ( '' === $from || '*' === $from || '-' === $from ) { return esc_html( $to ); } return '≥ ' . esc_html( $from ) . ' – ' . esc_html( $to ); } return esc_html( $v ); } /** * Return an img tag for a component-type icon. * * @since 5.0.0 * * @param string $type Component type: plugin, theme, core, php, apache, nginx, mariadb, mysql, imagemagick, curl, memcached, redis, sqlite. * @return string HTML img tag with class wpvuln-component-icon, or empty string. */ function wpvulnerability_component_icon_html( $type ) { $icon_map = array( 'plugin' => 'icon-plugin.svg', 'theme' => 'icon-theme.svg', 'core' => 'icon-wordpress.svg', 'php' => 'icon-php.svg', 'apache' => 'icon-apache.svg', 'nginx' => 'icon-nginx.svg', 'mariadb' => 'icon-mariadb.svg', 'mysql' => 'icon-mysql.svg', 'imagemagick' => 'icon-imagemagick.svg', 'curl' => 'icon-curl.svg', 'memcached' => 'icon-memcached.svg', 'redis' => 'icon-redis.svg', 'sqlite' => 'icon-sqlite.svg', ); if ( ! isset( $icon_map[ $type ] ) ) { return ''; } return ''; } /** * Convert vulnerabilities into pretty HTML * * @since 2.0.0 * * @param string $type Type: core, plugin, theme, php, apache, nginx, mariadb, mysql, imagemagick, curl. * @param array $vulnerabilities Vulnerability data. * * @return string The HTML representation of vulnerabilities. */ function wpvulnerability_html( $type, $vulnerabilities ) { $html = ''; if ( in_array( $type, array( 'plugin', 'theme' ), true ) ) { foreach ( $vulnerabilities as $vulnerability ) { if ( ! is_array( $vulnerability ) ) { continue; } $vuln_impact_raw = $vulnerability['impact'] ?? null; $vuln_impact = is_array( $vuln_impact_raw ) ? $vuln_impact_raw : array(); $vuln_cvss_raw = $vuln_impact['cvss'] ?? null; $vuln_cvss = is_array( $vuln_cvss_raw ) ? $vuln_cvss_raw : array(); $vuln_cvss2_raw = $vuln_impact['cvss2'] ?? null; $vuln_cvss2 = is_array( $vuln_cvss2_raw ) ? $vuln_cvss2_raw : array(); $vuln_cvss3_raw = $vuln_impact['cvss3'] ?? null; $vuln_cvss3 = is_array( $vuln_cvss3_raw ) ? $vuln_cvss3_raw : array(); $vuln_cvss4_raw = $vuln_impact['cvss4'] ?? null; $vuln_cvss4 = is_array( $vuln_cvss4_raw ) ? $vuln_cvss4_raw : array(); $vuln_ssvc_raw = $vuln_impact['ssvc'] ?? null; $vuln_ssvc = is_array( $vuln_ssvc_raw ) ? $vuln_ssvc_raw : array(); $vuln_cwe_raw = $vuln_impact['cwe'] ?? null; $vuln_cwe = is_array( $vuln_cwe_raw ) ? $vuln_cwe_raw : array(); $vuln_src_raw = $vulnerability['source'] ?? null; $vuln_sources = is_array( $vuln_src_raw ) ? $vuln_src_raw : array(); $kev = ( isset( $vuln_ssvc['kev'] ) && true === $vuln_ssvc['kev'] ); $exploitation = isset( $vuln_ssvc['exploitation'] ) && is_string( $vuln_ssvc['exploitation'] ) ? $vuln_ssvc['exploitation'] : ''; $automatable = isset( $vuln_ssvc['automatable'] ) && is_string( $vuln_ssvc['automatable'] ) ? $vuln_ssvc['automatable'] : ''; $kev_date_raw = $vuln_ssvc['kev_date'] ?? null; $kev_date = is_string( $kev_date_raw ) && '' !== $kev_date_raw ? $kev_date_raw : null; $epss_raw = $vuln_impact['epss'] ?? null; $epss = is_numeric( $epss_raw ) ? (float) $epss_raw : null; $description = wpvulnerability_get_source_description( $vuln_sources ); $what = array(); foreach ( $vuln_cwe as $vulnerability_cwe ) { if ( ! is_array( $vulnerability_cwe ) ) { continue; } $cwe_name = is_scalar( $vulnerability_cwe['name'] ?? '' ) ? (string) ( $vulnerability_cwe['name'] ?? '' ) : ''; $cwe_desc = is_scalar( $vulnerability_cwe['description'] ?? '' ) ? (string) ( $vulnerability_cwe['description'] ?? '' ) : ''; $what[] = '
' . wp_kses( $cwe_name, 'strip' ) . '
' . esc_html( $cwe_desc ) . '
'; } $source = wpvulnerability_render_source_pills( $vuln_sources ); // Best available CVSS score and severity: cvss4 > cvss3 > cvss2 > legacy cvss. $score = null; $sev_raw = null; foreach ( array( $vuln_cvss4, $vuln_cvss3, $vuln_cvss2, $vuln_cvss ) as $cvss_c ) { if ( empty( $cvss_c ) ) { continue; } $s_raw = $cvss_c['score'] ?? null; $v_raw = $cvss_c['severity'] ?? null; $s = is_numeric( $s_raw ) ? number_format( (float) $s_raw, 1, '.', '' ) : null; $v = is_string( $v_raw ) && '' !== $v_raw ? $v_raw : null; if ( null !== $s || null !== $v ) { $score = $s; $sev_raw = $v; break; } } $vuln_name = is_scalar( $vulnerability['name'] ?? '' ) ? (string) ( $vulnerability['name'] ?? '' ) : ''; $html .= '

' . wp_kses( $vuln_name, 'strip' ) . '

'; $vuln_closed = is_numeric( $vulnerability['closed'] ?? 0 ) ? (int) ( $vulnerability['closed'] ?? 0 ) : 0; $vuln_unfixed = is_numeric( $vulnerability['unfixed'] ?? 0 ) ? (int) ( $vulnerability['unfixed'] ?? 0 ) : 0; $score_badge = wpvulnerability_render_score_badge( $score, $sev_raw, $epss ); $show_active = $kev || 'active' === $exploitation; $show_poc = 'poc' === $exploitation; $show_auto = 'yes' === $automatable; if ( $show_active || $show_poc || $show_auto || '' !== $score_badge ) { $html .= '
'; if ( $show_active ) { $html .= '⚠ ' . esc_html__( 'Actively exploited', 'wpvulnerability' ); if ( $kev && null !== $kev_date ) { $html .= ' · ' . esc_html( $kev_date ); } $html .= ''; } if ( $show_poc ) { $html .= '⚡ ' . esc_html__( 'Public exploit', 'wpvulnerability' ) . ''; } if ( $show_auto ) { $html .= '⚙ ' . esc_html__( 'Automatable', 'wpvulnerability' ) . ''; } if ( '' !== $score_badge ) { $html .= $score_badge; } $html .= '
'; } if ( null !== $description ) { $html .= '
' . esc_html( $description ) . '
'; } if ( $vuln_closed || $vuln_unfixed ) { $html .= '
'; if ( $vuln_closed ) { $html .= '
' . esc_html__( 'This plugin is closed. Please replace it with another.', 'wpvulnerability' ) . '
'; } if ( $vuln_unfixed ) { $html .= '
' . esc_html__( 'This vulnerability appears to be unpatched. Stay tuned for upcoming plugin updates.', 'wpvulnerability' ) . '
'; } $html .= '
'; } if ( count( $what ) ) { $html .= '
' . implode( '', $what ) . '
'; } if ( '' !== $source ) { $html .= '
' . esc_html__( 'References:', 'wpvulnerability' ) . ''; $html .= $source; $html .= '
'; } } } elseif ( 'core' === $type ) { foreach ( $vulnerabilities as $vulnerability ) { if ( ! is_array( $vulnerability ) ) { continue; } $vuln_impact_raw = $vulnerability['impact'] ?? null; $vuln_impact = is_array( $vuln_impact_raw ) ? $vuln_impact_raw : array(); $vuln_cvss_raw = $vuln_impact['cvss'] ?? null; $vuln_cvss = is_array( $vuln_cvss_raw ) ? $vuln_cvss_raw : array(); $vuln_cvss2_raw = $vuln_impact['cvss2'] ?? null; $vuln_cvss2 = is_array( $vuln_cvss2_raw ) ? $vuln_cvss2_raw : array(); $vuln_cvss3_raw = $vuln_impact['cvss3'] ?? null; $vuln_cvss3 = is_array( $vuln_cvss3_raw ) ? $vuln_cvss3_raw : array(); $vuln_cvss4_raw = $vuln_impact['cvss4'] ?? null; $vuln_cvss4 = is_array( $vuln_cvss4_raw ) ? $vuln_cvss4_raw : array(); $vuln_ssvc_raw = $vuln_impact['ssvc'] ?? null; $vuln_ssvc = is_array( $vuln_ssvc_raw ) ? $vuln_ssvc_raw : array(); $vuln_cwe_raw = $vuln_impact['cwe'] ?? null; $vuln_cwe = is_array( $vuln_cwe_raw ) ? $vuln_cwe_raw : array(); $vuln_src_raw = $vulnerability['source'] ?? null; $vuln_sources = is_array( $vuln_src_raw ) ? $vuln_src_raw : array(); $kev = ( isset( $vuln_ssvc['kev'] ) && true === $vuln_ssvc['kev'] ); $exploitation = isset( $vuln_ssvc['exploitation'] ) && is_string( $vuln_ssvc['exploitation'] ) ? $vuln_ssvc['exploitation'] : ''; $automatable = isset( $vuln_ssvc['automatable'] ) && is_string( $vuln_ssvc['automatable'] ) ? $vuln_ssvc['automatable'] : ''; $kev_date_raw = $vuln_ssvc['kev_date'] ?? null; $kev_date = is_string( $kev_date_raw ) && '' !== $kev_date_raw ? $kev_date_raw : null; $epss_raw = $vuln_impact['epss'] ?? null; $epss = is_numeric( $epss_raw ) ? (float) $epss_raw : null; $description = wpvulnerability_get_source_description( $vuln_sources ); $what = array(); foreach ( $vuln_cwe as $vulnerability_cwe ) { if ( ! is_array( $vulnerability_cwe ) ) { continue; } $cwe_name = is_scalar( $vulnerability_cwe['name'] ?? '' ) ? (string) ( $vulnerability_cwe['name'] ?? '' ) : ''; $cwe_desc = is_scalar( $vulnerability_cwe['description'] ?? '' ) ? (string) ( $vulnerability_cwe['description'] ?? '' ) : ''; $what[] = '
' . wp_kses( $cwe_name, 'strip' ) . '
' . esc_html( $cwe_desc ) . '
'; } $source = wpvulnerability_render_source_pills( $vuln_sources ); // Best available CVSS score and severity: cvss4 > cvss3 > cvss2 > legacy cvss. $score = null; $sev_raw = null; foreach ( array( $vuln_cvss4, $vuln_cvss3, $vuln_cvss2, $vuln_cvss ) as $cvss_c ) { if ( empty( $cvss_c ) ) { continue; } $s_raw = $cvss_c['score'] ?? null; $v_raw = $cvss_c['severity'] ?? null; $s = is_numeric( $s_raw ) ? number_format( (float) $s_raw, 1, '.', '' ) : null; $v = is_string( $v_raw ) && '' !== $v_raw ? $v_raw : null; if ( null !== $s || null !== $v ) { $score = $s; $sev_raw = $v; break; } } $vuln_name = is_scalar( $vulnerability['name'] ?? '' ) ? (string) ( $vulnerability['name'] ?? '' ) : ''; $html .= '

' . wpvulnerability_component_icon_html( 'core' ) . ' WordPress ' . wp_kses( $vuln_name, 'strip' ) . '

'; $score_badge = wpvulnerability_render_score_badge( $score, $sev_raw, $epss ); $show_active = $kev || 'active' === $exploitation; $show_poc = 'poc' === $exploitation; $show_auto = 'yes' === $automatable; if ( $show_active || $show_poc || $show_auto || '' !== $score_badge ) { $html .= '
'; if ( $show_active ) { $html .= '⚠ ' . esc_html__( 'Actively exploited', 'wpvulnerability' ); if ( $kev && null !== $kev_date ) { $html .= ' · ' . esc_html( $kev_date ); } $html .= ''; } if ( $show_poc ) { $html .= '⚡ ' . esc_html__( 'Public exploit', 'wpvulnerability' ) . ''; } if ( $show_auto ) { $html .= '⚙ ' . esc_html__( 'Automatable', 'wpvulnerability' ) . ''; } if ( '' !== $score_badge ) { $html .= $score_badge; } $html .= '
'; } if ( null !== $description ) { $html .= '
' . esc_html( $description ) . '
'; } if ( count( $what ) ) { $html .= '
' . implode( '', $what ) . '
'; } if ( '' !== $source ) { $html .= '
' . esc_html__( 'References:', 'wpvulnerability' ) . ''; $html .= $source; $html .= '
'; } } } elseif ( in_array( $type, array( 'php', 'apache', 'nginx', 'mariadb', 'mysql', 'imagemagick', 'curl', 'memcached', 'redis', 'sqlite' ), true ) ) { foreach ( $vulnerabilities as $vulnerability ) { if ( ! is_array( $vulnerability ) ) { continue; } $vuln_impact_raw = $vulnerability['impact'] ?? null; $vuln_impact = is_array( $vuln_impact_raw ) ? $vuln_impact_raw : array(); $vuln_cvss2_raw = $vuln_impact['cvss2'] ?? null; $vuln_cvss2 = is_array( $vuln_cvss2_raw ) ? $vuln_cvss2_raw : array(); $vuln_cvss3_raw = $vuln_impact['cvss3'] ?? null; $vuln_cvss3 = is_array( $vuln_cvss3_raw ) ? $vuln_cvss3_raw : array(); $vuln_cvss4_raw = $vuln_impact['cvss4'] ?? null; $vuln_cvss4 = is_array( $vuln_cvss4_raw ) ? $vuln_cvss4_raw : array(); $vuln_cwe_raw = $vuln_impact['cwe'] ?? null; $vuln_cwe = is_array( $vuln_cwe_raw ) ? $vuln_cwe_raw : array(); $vuln_src_raw = $vulnerability['source'] ?? null; $vuln_sources = is_array( $vuln_src_raw ) ? $vuln_src_raw : array(); // For software endpoints, kev is at impact.kev (not inside ssvc). $kev = ( isset( $vuln_impact['kev'] ) && true === $vuln_impact['kev'] ); $description = wpvulnerability_get_source_description( $vuln_sources ); $what = array(); foreach ( $vuln_cwe as $vulnerability_cwe ) { if ( ! is_array( $vulnerability_cwe ) ) { continue; } $cwe_name = is_scalar( $vulnerability_cwe['name'] ?? '' ) ? (string) ( $vulnerability_cwe['name'] ?? '' ) : ''; $cwe_desc = is_scalar( $vulnerability_cwe['description'] ?? '' ) ? (string) ( $vulnerability_cwe['description'] ?? '' ) : ''; $what[] = '
' . wp_kses( $cwe_name, 'strip' ) . '
' . esc_html( $cwe_desc ) . '
'; } $source = wpvulnerability_render_source_pills( $vuln_sources ); // Best available CVSS score and severity: cvss4 > cvss3 > cvss2. $score = null; $sev_raw = null; foreach ( array( $vuln_cvss4, $vuln_cvss3, $vuln_cvss2 ) as $cvss_c ) { if ( empty( $cvss_c ) ) { continue; } $s_raw = $cvss_c['score'] ?? null; $v_raw = $cvss_c['severity'] ?? null; $s = is_numeric( $s_raw ) ? number_format( (float) $s_raw, 1, '.', '' ) : null; $v = is_string( $v_raw ) && '' !== $v_raw ? $v_raw : null; if ( null !== $s || null !== $v ) { $score = $s; $sev_raw = $v; break; } } $vuln_name = is_scalar( $vulnerability['name'] ?? '' ) ? (string) ( $vulnerability['name'] ?? '' ) : ''; $html .= '

' . wp_kses( $vuln_name, 'strip' ) . '

'; $score_badge = wpvulnerability_render_score_badge( $score, $sev_raw ); if ( $kev || '' !== $score_badge ) { $html .= '
'; if ( $kev ) { $html .= '⚠ ' . esc_html__( 'Actively exploited', 'wpvulnerability' ) . ''; } if ( '' !== $score_badge ) { $html .= $score_badge; } $html .= '
'; } if ( null !== $description ) { $html .= '
' . esc_html( $description ) . '
'; } if ( count( $what ) ) { $html .= '
' . implode( '', $what ) . '
'; } if ( '' !== $source ) { $html .= '
' . esc_html__( 'References:', 'wpvulnerability' ) . ''; $html .= $source; $html .= '
'; } } } return $html; } /** * Convert vulnerabilities into HTML format. * * @since 3.5.0 * * @param string $type Type of software (php, apache, nginx, mariadb, mysql, imagemagick, curl). * @return string|false The HTML output if vulnerabilities were found, false otherwise. */ function wpvulnerability_html_software( $type ) { $html = ''; $found = false; $software_name = null; // Map software types to their names. $software_names = array( 'php' => 'PHP', 'apache' => 'Apache HTTP', 'nginx' => 'Nginx', 'mariadb' => 'MariaDB', 'mysql' => 'MySQL', 'imagemagick' => 'ImageMagick', 'curl' => 'curl', 'memcached' => 'memcached', 'redis' => 'redis', 'sqlite' => 'sqlite', ); // Check if the type is valid and get the software name. if ( isset( $software_names[ $type ] ) ) { $software_name = $software_names[ $type ]; } else { return false; // Invalid type. } $version = wpvulnerability_sanitize_and_validate_version( wpvulnerability_get_software_version( $type ) ); $software_data = wpvulnerability_software_get_vulnerabilities( $type ); $vulnerabilities = array(); if ( is_array( $software_data ) && isset( $software_data['vulnerabilities'] ) && is_array( $software_data['vulnerabilities'] ) ) { $vulnerabilities = $software_data['vulnerabilities']; } // Check if vulnerabilities were found. if ( 0 < count( $vulnerabilities ) ) { $found = true; // translators: %s: software name. $html .= '

' . wpvulnerability_component_icon_html( $type ) . sprintf( esc_html__( '%s running', 'wpvulnerability' ), esc_html( $software_name ) ) . ': ' . wp_kses( (string) $version, 'strip' ) . '

'; // Show lifecycle status if available. $lifecycle = isset( $software_data['lifecycle'] ) && is_array( $software_data['lifecycle'] ) ? $software_data['lifecycle'] : array(); $lc_status = is_scalar( $lifecycle['status'] ?? '' ) ? (string) ( $lifecycle['status'] ?? '' ) : ''; $lc_date_end = is_scalar( $lifecycle['date_end'] ?? '' ) ? (string) ( $lifecycle['date_end'] ?? '' ) : ''; if ( 'e' === $lc_status || 's' === $lc_status ) { $html .= '
'; if ( 'e' === $lc_status ) { $html .= '● ' . esc_html__( 'End of Life', 'wpvulnerability' ) . ''; if ( '' !== $lc_date_end ) { $html .= ' — ' . esc_html__( 'End of life:', 'wpvulnerability' ) . ' ' . esc_html( $lc_date_end ) . ''; } } else { $html .= '● ' . esc_html__( 'Supported', 'wpvulnerability' ) . ''; if ( '' !== $lc_date_end ) { $html .= ' — ' . esc_html__( 'End of life:', 'wpvulnerability' ) . ' ' . esc_html( $lc_date_end ); } } $html .= '
'; } $html .= wpvulnerability_html( $type, $vulnerabilities ); } return $found ? $html : false; } /** * Convert plugin vulnerabilities into HTML format. * * @since 2.0.0 * * @return string|false The HTML output if plugin vulnerabilities were found, false otherwise. */ function wpvulnerability_html_plugins() { $html = ''; $found = false; $plugins = wpvulnerability_plugin_get_vulnerabilities(); foreach ( $plugins as $file_path => $plugin_data ) { if ( ! is_array( $plugin_data ) ) { continue; } // Check if the plugin is marked as vulnerable. if ( isset( $plugin_data['vulnerable'] ) && 1 === $plugin_data['vulnerable'] ) { $found = true; // Generate HTML markup for the plugin vulnerability. $plugin_name = is_scalar( $plugin_data['Name'] ?? '' ) ? (string) ( $plugin_data['Name'] ?? '' ) : ''; $html .= '

' . wpvulnerability_component_icon_html( 'plugin' ) . esc_html__( 'Plugin', 'wpvulnerability' ) . ': ' . wp_kses( $plugin_name, 'strip' ) . '

'; $plugin_vulns = isset( $plugin_data['vulnerabilities'] ) && is_array( $plugin_data['vulnerabilities'] ) ? $plugin_data['vulnerabilities'] : array(); $html .= wpvulnerability_html( 'plugin', $plugin_vulns ); } } // Return the HTML if vulnerabilities were found. return $found ? $html : false; } /** * Convert plugin vulnerabilities into list format. * * @since 2.2.0 * * @return string|false The HTML output if plugin vulnerabilities were found, false otherwise. */ function wpvulnerability_list_plugins() { $html = ''; // Return the HTML if vulnerabilities were found. return $found ? $html : false; } /** * Convert theme vulnerabilities into HTML format. * * @since 2.0.0 * * @return string|false The HTML output if theme vulnerabilities were found, false otherwise. */ function wpvulnerability_html_themes() { $html = ''; $found = false; // Get vulnerabilities data for themes. $themes = wpvulnerability_theme_get_vulnerabilities(); // Iterate through each theme's data. foreach ( $themes as $theme_data ) { if ( ! is_array( $theme_data ) ) { continue; } $td_wpv = isset( $theme_data['wpvulnerability'] ) && is_array( $theme_data['wpvulnerability'] ) ? $theme_data['wpvulnerability'] : array(); // Check if the theme is marked as vulnerable. if ( isset( $td_wpv['vulnerable'] ) && 1 === ( is_numeric( $td_wpv['vulnerable'] ) ? (int) $td_wpv['vulnerable'] : 0 ) ) { $found = true; // Generate HTML markup for the theme vulnerability. $theme_name = is_scalar( $td_wpv['name'] ?? '' ) ? (string) ( $td_wpv['name'] ?? '' ) : ''; $html .= '

' . wpvulnerability_component_icon_html( 'theme' ) . esc_html__( 'Theme', 'wpvulnerability' ) . ': ' . wp_kses( $theme_name, 'strip' ) . '

'; $vuln_list = isset( $td_wpv['vulnerabilities'] ) && is_array( $td_wpv['vulnerabilities'] ) ? $td_wpv['vulnerabilities'] : array(); $html .= wpvulnerability_html( 'theme', $vuln_list ); } } // Return the HTML if vulnerabilities were found. return $found ? $html : false; } /** * Convert theme vulnerabilities into list format. * * @since 2.2.0 * * @return string|false The HTML output if theme vulnerabilities were found, false otherwise. */ function wpvulnerability_list_themes() { $html = ''; // Return the HTML if vulnerabilities were found. return $found ? $html : false; } /** * Returns an EOL badge HTML span for a software component. * * Reads the cached lifecycle data for the given software type and returns * a styled badge when the component has reached end-of-life status. * * @since 5.0.0 * * @param string $type The software type (e.g., 'php', 'apache', 'mariadb'). * * @return string HTML badge string, or empty string if not EOL or no data. */ function wpvulnerability_eol_badge_html( $type ) { $sw_data = wpvulnerability_software_get_vulnerabilities( $type ); $lc = isset( $sw_data['lifecycle'] ) && is_array( $sw_data['lifecycle'] ) ? $sw_data['lifecycle'] : array(); $status = is_scalar( $lc['status'] ?? '' ) ? (string) ( $lc['status'] ?? '' ) : ''; $date_end = is_scalar( $lc['date_end'] ?? '' ) ? (string) ( $lc['date_end'] ?? '' ) : ''; if ( 'e' !== $status ) { return ''; } if ( '' !== $date_end ) { /* translators: %s: end-of-life date */ $title = sprintf( __( 'End of life: %s', 'wpvulnerability' ), $date_end ); } else { $title = __( 'End of Life', 'wpvulnerability' ); } return '' . esc_html__( 'EOL', 'wpvulnerability' ) . ''; } /** * Convert core vulnerabilities into HTML format. * * @since 2.0.0 * * @return string|false The HTML output if core vulnerabilities were found, false otherwise. */ function wpvulnerability_html_core() { $html = ''; $found = false; // Get vulnerabilities data for WordPress core. $core = wpvulnerability_core_get_vulnerabilities(); // Check if there are any vulnerabilities. if ( count( $core ) ) { $found = true; // Generate HTML markup for the core vulnerabilities. $html .= wpvulnerability_html( 'core', $core ); } // Return the HTML if vulnerabilities were found. return $found ? $html : false; }