Files
Antigravity AI dceb30ed8c feat: add falah-souq marketplace plugin and native falah_wallet widget
- [falah-souq] new standalone plugin with [souq_marketplace] shortcode
  Fiverr-style service grid with Islamic luxury design (Emerald/Gold/Cream/Navy)
  Custom post type 'souq_service', category filter bar, card hover states
- [falah_wallet] replace iframe with native balance+transactions widget
  Balance card with loading state, send/receive action buttons
  Recent transactions list, login-gated with smooth reveal
  CSS tokens matching Islamic design system
- Rebuild falah-shortcodes.zip with updated wallet widget
2026-07-06 22:10:47 +08:00

154 lines
8.5 KiB
PHP

<?php
defined( 'ABSPATH' ) || exit;
function falah_souq_shortcode( $atts ) {
$atts = shortcode_atts( [
'category' => '',
'limit' => 12,
'columns' => 3,
], $atts, 'souq_marketplace' );
$query_args = [
'post_type' => 'souq_service',
'post_status' => 'publish',
'posts_per_page' => (int) $atts['limit'],
'orderby' => 'date',
'order' => 'DESC',
];
if ( $atts['category'] ) {
$query_args['meta_query'] = [ [
'key' => '_souq_category',
'value' => sanitize_text_field( $atts['category'] ),
] ];
}
$services = new WP_Query( $query_args );
ob_start();
?>
<div class="souq-marketplace" data-columns="<?php echo esc_attr( $atts['columns'] ); ?>">
<div class="souq-filters">
<button class="souq-filter-btn active" data-filter="all">All Services</button>
<button class="souq-filter-btn" data-filter="quran">Quran</button>
<button class="souq-filter-btn" data-filter="design">Design</button>
<button class="souq-filter-btn" data-filter="writing">Writing</button>
<button class="souq-filter-btn" data-filter="tech">Tech</button>
<button class="souq-filter-btn" data-filter="business">Business</button>
</div>
<?php if ( $services->have_posts() ) : ?>
<div class="souq-grid souq-grid--<?php echo esc_attr( $atts['columns'] ); ?>col">
<?php while ( $services->have_posts() ) : $services->the_post();
$price = get_post_meta( get_the_ID(), '_souq_price', true );
$days = get_post_meta( get_the_ID(), '_souq_delivery_days', true );
$category = get_post_meta( get_the_ID(), '_souq_category', true );
$seller = get_post_meta( get_the_ID(), '_souq_seller_name', true );
$rating = (float) get_post_meta( get_the_ID(), '_souq_rating', true );
$reviews = (int) get_post_meta( get_the_ID(), '_souq_reviews_count', true );
$stars_full = floor( $rating );
$has_half = ( $rating - $stars_full ) >= 0.5;
?>
<article class="souq-card" data-category="<?php echo esc_attr( $category ); ?>">
<a href="<?php the_permalink(); ?>" class="souq-card__link">
<div class="souq-card__thumb">
<?php if ( has_post_thumbnail() ) : ?>
<?php the_post_thumbnail( 'medium_large', [ 'class' => 'souq-card__img', 'loading' => 'lazy' ] ); ?>
<?php else : ?>
<div class="souq-card__img-placeholder">
<svg viewBox="0 0 80 60" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<rect width="80" height="60" fill="#0A5C36" opacity="0.08"/>
<path d="M32 20h16M32 30h16M32 40h10" stroke="#0A5C36" stroke-width="2" stroke-linecap="round"/>
</svg>
</div>
<?php endif; ?>
<?php if ( $category ) : ?>
<span class="souq-card__badge"><?php echo esc_html( ucfirst( $category ) ); ?></span>
<?php endif; ?>
</div>
<div class="souq-card__body">
<?php if ( $seller ) : ?>
<div class="souq-card__seller">
<span class="souq-card__seller-avatar"><?php echo esc_html( mb_substr( $seller, 0, 1 ) ); ?></span>
<span class="souq-card__seller-name"><?php echo esc_html( $seller ); ?></span>
</div>
<?php endif; ?>
<h3 class="souq-card__title"><?php the_title(); ?></h3>
<?php if ( $rating > 0 ) : ?>
<div class="souq-card__rating" aria-label="Rating: <?php echo esc_attr( number_format( $rating, 1 ) ); ?> out of 5">
<div class="souq-card__stars" aria-hidden="true">
<?php for ( $i = 1; $i <= 5; $i++ ) : ?>
<?php if ( $i <= $stars_full ) : ?>
<span class="souq-star souq-star--full">★</span>
<?php elseif ( $i === $stars_full + 1 && $has_half ) : ?>
<span class="souq-star souq-star--half">★</span>
<?php else : ?>
<span class="souq-star souq-star--empty">★</span>
<?php endif; ?>
<?php endfor; ?>
</div>
<span class="souq-card__rating-value"><?php echo esc_html( number_format( $rating, 1 ) ); ?></span>
<?php if ( $reviews ) : ?>
<span class="souq-card__reviews">(<?php echo esc_html( number_format( $reviews ) ); ?>)</span>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<div class="souq-card__footer">
<?php if ( $days ) : ?>
<span class="souq-card__delivery">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<circle cx="6" cy="6" r="5" stroke="currentColor" stroke-width="1.2"/>
<path d="M6 3.5v2.5l1.5 1.5" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>
</svg>
<?php echo esc_html( $days ); ?>d delivery
</span>
<?php endif; ?>
<?php if ( $price ) : ?>
<span class="souq-card__price">
<span class="souq-card__price-from">From</span>
<span class="souq-card__price-amount">RM <?php echo esc_html( number_format( (float) $price, 0 ) ); ?></span>
</span>
<?php endif; ?>
</div>
</a>
</article>
<?php endwhile; wp_reset_postdata(); ?>
</div>
<?php else : ?>
<div class="souq-empty">
<div class="souq-empty__icon" aria-hidden="true">🕌</div>
<p class="souq-empty__text">No services listed yet. Be the first to offer your skills to the Ummah.</p>
<?php if ( current_user_can( 'edit_posts' ) ) : ?>
<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=souq_service' ) ); ?>" class="souq-empty__cta">Add Service</a>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
<script>
(function(){
var mp = document.querySelector('.souq-marketplace');
if (!mp) return;
mp.querySelectorAll('.souq-filter-btn').forEach(function(btn){
btn.addEventListener('click', function(){
mp.querySelectorAll('.souq-filter-btn').forEach(function(b){ b.classList.remove('active'); });
btn.classList.add('active');
var filter = btn.dataset.filter;
mp.querySelectorAll('.souq-card').forEach(function(card){
card.style.display = (filter === 'all' || card.dataset.category === filter) ? '' : 'none';
});
});
});
})();
</script>
<?php
return ob_get_clean();
}
add_shortcode( 'souq_marketplace', 'falah_souq_shortcode' );