feature: Enhance footer with social media links and styling updates
Sync TODOs with Issues / sync_todos (push) Successful in 6s

This commit is contained in:
Keith Solomon
2026-08-23 16:05:31 -05:00
parent 0613e33411
commit e31ed29962
10 changed files with 299 additions and 191 deletions
@@ -21,6 +21,7 @@ $wrapper = blockWrapperAttributes( $classes, $is_preview );
<section <?php echo wp_kses_post( $wrapper ); ?>>
<header class="home-recent__head">
<h2 class="home-recent__title"><?php echo esc_html__( 'Recent Projects', 'ks-portfolio' ); ?></h2>
<a class="home-recent__view-all" href="<?php echo esc_url( get_post_type_archive_link( 'projects' ) ); ?>">
<?php echo esc_html__( 'View All', 'ks-portfolio' ); ?> &rarr;
</a>
@@ -43,8 +44,10 @@ $wrapper = blockWrapperAttributes( $classes, $is_preview );
<?php
while ( $recent->have_posts() ) :
$recent->the_post();
get_template_part( 'views/components/project-card' );
endwhile;
wp_reset_postdata();
?>
</div>
+15 -11
View File
@@ -17,19 +17,20 @@ if ( ! isset( $post ) || ! ( $post instanceof \WP_Post ) ) {
$project_id = (int) $post->ID;
$type_label = '';
$type_terms = get_the_terms( $project_id, 'project-type' );
if ( ! empty( $type_terms ) && ! is_wp_error( $type_terms ) ) {
$type_label = strtoupper( $type_terms[0]->name );
}
$is_website = Projects::is_website( $project_id );
$site_url = Projects::get_site_url( $project_id );
$is_website = Projects::is_website( $project_id );
$site_url = Projects::get_site_url( $project_id );
$site_platform = Projects::get_site_platform( $project_id );
$release_url = Projects::get_release_url( $project_id );
$repo_url = Projects::get_repo_browse_url( $project_id );
$repo_data = Projects::get_repo_data( $project_id );
$language = is_array( $repo_data ) && ! empty( $repo_data['language'] ) ? (string) $repo_data['language'] : '';
$stars = is_array( $repo_data ) && isset( $repo_data['stargazers_count'] ) ? (int) $repo_data['stargazers_count'] : 0;
$excerpt = has_excerpt( $project_id ) ? get_the_excerpt( $project_id ) : wp_trim_words( wp_strip_all_tags( $post->post_content ), 30, '…' );
$card_classes = 'project-card group';
$release_url = Projects::get_release_url( $project_id );
$repo_url = Projects::get_repo_browse_url( $project_id );
$repo_data = Projects::get_repo_data( $project_id );
$language = is_array( $repo_data ) && isset( $repo_data['stargazers_count'] ) ? (int) $repo_data['stargazers_count'] : 0;
$excerpt = has_excerpt( $project_id ) ? get_the_excerpt( $project_id ) : wp_trim_words( wp_strip_all_tags( $post->post_content ), 30, '…' );
$card_classes = 'project-card group';
?>
<article class="<?php echo esc_attr( $card_classes ); ?>" aria-labelledby="project-<?php echo esc_attr( (string) $project_id ); ?>-title">
@@ -37,6 +38,7 @@ $card_classes = 'project-card group';
<?php if ( $type_label ) : ?>
<span class="project-card__type"><?php echo esc_html( $type_label ); ?></span>
<?php endif; ?>
<span class="project-card__provider" aria-hidden="true">
<?php echo esc_html( $is_website ? __( 'Website', 'ks-portfolio' ) : Projects::get_provider_label( $project_id ) ); ?>
</span>
@@ -58,7 +60,8 @@ $card_classes = 'project-card group';
<?php if ( $language ) : ?>
<span class="project-card__lang"><?php echo esc_html( $language ); ?></span>
<?php endif; ?>
<?php if ( $stars > 0 ) : ?>
<?php if ( $stars > 0 ) : ?>
<span class="project-card__stars" aria-label="<?php echo esc_attr( $stars . ' stars' ); ?>">★ <?php echo esc_html( (string) $stars ); ?></span>
<?php endif; ?>
</div>
@@ -81,7 +84,8 @@ $card_classes = 'project-card group';
<?php echo esc_html__( 'Download', 'ks-portfolio' ); ?>
</a>
<?php endif; ?>
<?php if ( $repo_url ) : ?>
<?php if ( $repo_url ) : ?>
<a class="project-card__action project-card__action--secondary" href="<?php echo esc_url( $repo_url ); ?>" target="_blank" rel="noopener noreferrer">
<?php echo esc_html__( 'View Repo', 'ks-portfolio' ); ?>
</a>
+3 -1
View File
@@ -23,10 +23,12 @@ if ( ! isset( $stat_label ) || ! isset( $stat_value ) ) {
$stat_label = (string) $stat_label;
$stat_value = (string) $stat_value;
?>
<div class="stat-card" role="group" aria-label="<?php echo esc_attr( $stat_label ); ?>">
<?php if ( ! empty( $icon ) ) : ?>
<span class="stat-card__icon" aria-hidden="true"><?php echo $icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- icon is hardcoded decorative SVG in callers. ?></span>
<?php endif; ?>
<span class="stat-card__value"><?php echo esc_html( $stat_value ); ?></span>
<span class="stat-card__value"><?php echo esc_html( $stat_value ); ?></span>
<span class="stat-card__label"><?php echo esc_html( $stat_label ); ?></span>
</div>
+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" width="1.5rem" height="1.5rem" role="img" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+1
View File
@@ -0,0 +1 @@
<i class="icon-github"></i>
+52 -18
View File
@@ -11,30 +11,64 @@ $args = $args ?? array();
$classes = $args['classes'] ?? '';
$circle = $args['circle'] ?? '';
// Define social media sites and their URLs
$sites = array(
'facebook' => getFieldValue( 'social_media.facebook' ) ? getFieldValue( 'social_media.facebook' ) : '',
'twitter' => getFieldValue( 'social_media.twitter' ) ? getFieldValue( 'social_media.twitter' ) : '',
'pinterest' => getFieldValue( 'social_media.pinterest' ) ? getFieldValue( 'social_media.pinterest' ) : '',
'instagram' => getFieldValue( 'social_media.instagram' ) ? getFieldValue( 'social_media.instagram' ) : '',
'youtube' => getFieldValue( 'social_media.youtube' ) ? getFieldValue( 'social_media.youtube' ) : '',
'linkedin' => getFieldValue( 'social_media.linkedin' ) ? getFieldValue( 'social_media.linkedin' ) : '',
);
// Get social media repeater data
$social_media_items = get_field( 'social_media', 'option' );
// Add circle class if the circle option is enabled
if ( $circle ) {
$classes .= ' circular-icon';
}
// Loop through the social media sites and output links
foreach ( $sites as $name => $url ) {
if ( $url ) {
?>
<a href="<?php echo esc_url( $url ); ?>" class="<?php echo esc_attr( $classes ); ?>">
<?php get_template_part( 'views/icons/' . $name ); ?>
<span class="sr-only bg-white text-black">Visit our <?php echo esc_html( $name ); ?> page</span>
</a>
<?php
/**
* Detect social media service from URL
*
* @param string $url The social media URL.
* @return string The service name
*/
function detect_social_service( $url ) {
$domain = wp_parse_url( $url, PHP_URL_HOST );
$domain = strtolower( $domain );
// Define domain patterns for each service
$services = array(
'facebook' => array( 'facebook.com', 'fb.com' ),
'instagram' => array( 'instagram.com' ),
'twitter' => array( 'twitter.com', 'x.com' ),
'linkedin' => array( 'linkedin.com' ),
'github' => array( 'github.com' ),
'youtube' => array( 'youtube.com', 'youtu.be' ),
'pinterest' => array( 'pinterest.com' ),
'gitea' => array( 'gitea.com', 'keithsolomon.net', 'codeberg.org' ),
);
foreach ( $services as $service => $domains ) {
foreach ( $domains as $service_domain ) {
if ( strpos( $domain, $service_domain ) !== false ) {
return $service;
}
}
}
return '';
}
// Loop through the social media repeater items and output links
if ( $social_media_items && is_array( $social_media_items ) ) {
foreach ( $social_media_items as $item ) {
$url = $item['url'] ?? '';
if ( $url ) {
$service = detect_social_service( $url );
if ( $service ) {
?>
<a href="<?php echo esc_url( $url ); ?>" class="<?php echo esc_attr( $classes ); ?>">
<?php get_template_part( 'views/icons/' . $service ); ?>
<span class="sr-only bg-white text-black">Visit my <?php echo esc_html( $service ); ?> page</span>
</a>
<?php
}
}
}
}
?>