Files
Portfolio-2026/lib/class-projects.php
T

140 lines
3.7 KiB
PHP

<?php
/**
* Project helper for the ks-portfolio theme.
*
* Thin wrapper around the projects-portfolio plugin's provider-aware
* helpers. Templates should call these methods instead of branching on
* provider, so the theme stays decoupled from GitHub/Gitea implementation
* details.
*
* Every accessor is safe to call whether the plugin is active or not: when
* the underlying function is missing or repo data is unavailable, defaults
* that match the documented data contract are returned.
*
* @package KsPortfolio
*/
namespace KsPortfolio;
class Projects {
/**
* Whether the projects-portfolio plugin is active.
*
* @return bool
*/
public static function is_plugin_active(): bool {
return function_exists( 'projects_portfolio_get_provider' );
}
/**
* Provider label for a project (e.g. 'GitHub', 'Gitea', or 'Unknown').
*
* @param int $post_id Project post ID.
* @return string
*/
public static function get_provider_label( int $post_id ): string {
if ( ! self::is_plugin_active() ) {
return 'Unknown';
}
$provider = projects_portfolio_get_provider( $post_id );
return method_exists( $provider, 'get_label' ) ? (string) $provider->get_label() : 'Unknown';
}
/**
* Release ZIP URL (or empty string).
*
* @param int $post_id Project post ID.
* @return string
*/
public static function get_release_url( int $post_id ): string {
if ( ! self::is_plugin_active() ) {
return '';
}
return (string) projects_portfolio_get_release_url( $post_id );
}
/**
* Public repository browse URL (or empty string).
*
* @param int $post_id Project post ID.
* @return string
*/
public static function get_repo_browse_url( int $post_id ): string {
if ( ! self::is_plugin_active() ) {
return '';
}
$provider = projects_portfolio_get_provider( $post_id );
return method_exists( $provider, 'get_repo_browse_url' ) ? (string) $provider->get_repo_browse_url() : '';
}
/**
* Normalized repository data array (or null).
*
* @param int $post_id Project post ID.
* @return array<string,mixed>|null
*/
public static function get_repo_data( int $post_id ) {
if ( ! self::is_plugin_active() ) {
return null;
}
$data = projects_portfolio_get_repo_data( $post_id );
return is_array( $data ) ? $data : null;
}
/**
* Owner data (avatar/login/html_url) or null.
*
* @param int $post_id Project post ID.
* @return array<string,mixed>|null
*/
public static function get_owner_data( int $post_id ) {
$data = self::get_repo_data( $post_id );
if ( ! $data || empty( $data['owner']['login'] ) ) {
return null;
}
return $data['owner'];
}
/**
* Latest release tag, or 'Unknown'.
*
* @param int $post_id Project post ID.
* @return string
*/
public static function get_latest_version( int $post_id ): string {
if ( ! self::is_plugin_active() ) {
return 'Unknown';
}
$provider = projects_portfolio_get_provider( $post_id );
return method_exists( $provider, 'get_latest_version' ) ? (string) $provider->get_latest_version() : 'Unknown';
}
/**
* Local download endpoint URL for the project.
*
* @param int $post_id Project post ID.
* @return string
*/
public static function get_download_url( int $post_id ): string {
return home_url( '/download/' . $post_id . '/' );
}
/**
* Render a stat-card-safe integer with optional formatting.
*
* @param mixed $value Raw repo stat value.
* @return string Display-safe string ('1.2k', '12,345', etc.) or '—' when empty.
*/
public static function format_stat( $value ): string {
if ( null === $value || '' === $value ) {
return '—';
}
$value = (int) $value;
if ( $value >= 10000 ) {
return number_format( $value / 1000, 1 ) . 'k';
}
return number_format( $value );
}
}