Skip to content
Kenya Coffee School

Kenya Coffee School

Teaching Coffee from #farm to #cup

  • Thika, Opposite Thika Gateway Plaza
  • +254 707 503 647 or Call +254 704 375 390
  • info@kenyacoffeeschool.golearn.co.ke
  • Home
  • Kenya coffee school – the best barista and specialty coffee school
  • KCS Info Hub
    • KCS/SCA Franchise Guidelines
      • Coffee Cupping Sensory Drills – organic acids
    • KCS Blogs
      • Kenya Coffee School – KCS & SCA Sensory Skills & Cupping Guide
        • Kenya Coffee School – Barista Skills Guide 4 weeks
        • KCS Coffee Cupping – Importance of Skimming
        • University of Coffee – MicroMasters in Coffee
    • Enroll Today
      • Kenya Coffee School Year 2026 Fee Structure
      • KCS Certification Exams
        • Exam Results :
      • More Professional Courses
        • Mixology and Bartending Course
    • Coffee Careers & Barista Jobs
    • Location and Directions
  • About KCS
    • Kenya Coffee School (KCS) Training Framework
    • Kenya Coffee School Founder
  • Projects
    • Kenya Youth & Women Coffee Farmers Innovation Hub (KYWCH)
    • Nairobi Coffee School(NCS)
  • Barista Mtaani Project
    • Barista Mtaani Education
  • Barista Mtaani Project
    • Marketplace
      • How Alfred Gitau Mwaura Built Kenya’s First Affordable Local Coffee Roaster
        • KCS – Specialty Coffee Academies (SCA)
      • Global Coffee Association (GCA) Certification Framework
        • GCA Certification Blockchain Integration Framework
        • GCA Tokenomics & Smart Contract Architecture
        • GCA Governance & IOT Design
        • GCA Coin Valuation & Stability Mechanism
        • KCS (Knowledge of Coffee Skills)
        • For Blockchain Tipping :
      • Direct Coffee Farmer Tipping System
      • GCA Certification
    • Barista Mtaani Coffee Auctions
  • Certifications
    • Volunteers in Coffee and Tea Tourism
    • Agroecosystems Kenya Coffee Project – by KCS
    • Kenya Coffee School – K.C.S (Knowledge of Coffee Skills) Certifications
    • Kenya Coffee School – Training on Digitalisation
    • Mixology & Bartending by Kenya Coffee School (KCS)
  • KCS Education
  • Shop at Kenya Coffee School
    • Coffee equipments, tools, and services offered by Kenya Coffee School
  • Why Train at Kenya Coffee School
    • Nairobi Coffee School(NCS) Hub2
    • Barista Mtaani for Juniors (BM4J Program)
    • Coffee & Business MBA
    • Kenya Youth & Women Coffee Farmers Innovation Hub (KYWCH)
    • Global Barista and Coffee Education
    • Kenya Coffee School Research Portfolio
  • Kenya Coffee Association: Brewing a Future Beyond the Cup
    • Kenya Barista Association
  • 2025 to 2030 KCS Courses and Programs
    • Kenya Coffee School: Barista Skills & Specialty Coffee Courses
    • More KCS Courses
      • The KCS Diploma in Gastronomic Sciences
        • 🎓 Diploma in Gastronomic Sciences in 12 Months
      • Fundamentals of Pastry & Confectionaries (MCP)
      • Applied Sciences in Coffee, Biodiversity & Sustainability
      • Learn Specialty Coffee & Agroecology
      • Managing Innovation Course at KCS
      • Kenya Coffee School – Mixology & Bartending Course
      • Coffee Open Data Courses at Kenya Coffee School
  • KCS Research Projects
    • Apply Global™ Milestones: A Decade of Impact
      • APPLY GLOBAL: Revolutionizing Hiring with Embedded QR-Powered e-Resumes
  • Mixology & Bartender Courses
  • News and Events Blog
    • Market Insights by Kenya Coffee School
  • Official Disclaimer — Kenya Coffee School
  • Transforming the Coffee Value Chain for Women and Youth
  • Kenya Coffee School App Download
KCS™ OSE™ 0

KCS Sandbox mode

Open Skills Education (OSE™)

Open Skills Education (OSE™) is a global skills equity framework

Open Skills Education (OSE™)

Open Skills Education (OSE™) Founding Charter Open Skills Education (OSE™)...

Blockchain Verification

Transaction Hash: 0x000…000

Block Number: –

Timestamp: –

Network: Polygon

Credential Hash: sha256-…

Excellent! You’ve created a perfect WordPress plugin foundation for **Barista Mtaani**. I’ll now add the complete approval workflow, public verification, and badge system to this plugin. ## 🚀 **NEXT: COMPLETE APPROVAL WORKFLOW + PUBLIC VERIFICATION** Here’s the **enhanced Barista Mtaani plugin** with all features from our unified credential system: ### **Updated Main Plugin File:** “`php get_charset_collate(); // Main Registry Table $table = $wpdb->prefix . BM_TABLE_PREFIX . ‘registry’; $sql = “CREATE TABLE $table ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, professional_id VARCHAR(50) NOT NULL, full_name VARCHAR(200) NOT NULL, email VARCHAR(200), phone VARCHAR(20), system VARCHAR(50) DEFAULT ‘SCB’, credential VARCHAR(200), level VARCHAR(50), issue_date DATE, expiry_date DATE, status VARCHAR(30) DEFAULT ‘pending’, registered_by VARCHAR(100), registered_date DATETIME DEFAULT CURRENT_TIMESTAMP, approved_by VARCHAR(100), approved_date DATETIME, revocation_reason TEXT, revoked_date DATETIME, badge_type VARCHAR(50), badge_image VARCHAR(500), qr_code VARCHAR(500), tx_hash VARCHAR(100), blockchain_network VARCHAR(50), metadata JSON, PRIMARY KEY (id), UNIQUE KEY professional_id (professional_id), KEY status (status), KEY system (system), KEY email (email) ) $charset;”; dbDelta( $sql ); // Audit Log Table $table = $wpdb->prefix . BM_TABLE_PREFIX . ‘audit_log’; $sql = “CREATE TABLE $table ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, action VARCHAR(100), professional_id VARCHAR(50), performed_by VARCHAR(100), user_ip VARCHAR(45), details TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY action (action), KEY professional_id (professional_id) ) $charset;”; dbDelta( $sql ); // Blockchain Transactions $table = $wpdb->prefix . BM_TABLE_PREFIX . ‘blockchain_tx’; $sql = “CREATE TABLE $table ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, tx_hash VARCHAR(100), professional_id VARCHAR(50), network VARCHAR(50), block_number BIGINT, timestamp DATETIME, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY tx_hash (tx_hash) ) $charset;”; dbDelta( $sql ); // Create default user roles self::create_roles(); } private static function create_roles() { // Registrar Role add_role( ‘bm_registrar’, __( ‘Barista Mtaani Registrar’, ‘barista-mtaani’ ), [ ‘read’ => true, ‘manage_bm_registry’ => true, ] ); // Approver Role add_role( ‘bm_approver’, __( ‘Barista Mtaani Approver’, ‘barista-mtaani’ ), [ ‘read’ => true, ‘manage_bm_approvals’ => true, ‘manage_bm_registry’ => true, ] ); // Add capabilities to admin $admin = get_role( ‘administrator’ ); if ( $admin ) { $admin->add_cap( ‘manage_bm_registry’ ); $admin->add_cap( ‘manage_bm_approvals’ ); $admin->add_cap( ‘manage_bm_settings’ ); } } public static function create_pages() { // Verification Page $verify_page = [ ‘post_title’ => ‘Verify Credential’, ‘post_content’ => ‘[bm_verify_credential]’, ‘post_status’ => ‘publish’, ‘post_type’ => ‘page’, ‘post_name’ => ‘verify-credential’, ]; $verify_id = wp_insert_post( $verify_page ); update_option( ‘bm_verify_page_id’, $verify_id ); // Public Registry Page $registry_page = [ ‘post_title’ => ‘Professional Registry’, ‘post_content’ => ‘[bm_public_registry]’, ‘post_status’ => ‘publish’, ‘post_type’ => ‘page’, ‘post_name’ => ‘professional-registry’, ]; $registry_id = wp_insert_post( $registry_page ); update_option( ‘bm_registry_page_id’, $registry_id ); } } “` ### **Database Handler Class:** “`php wpdb = $wpdb; $this->registry_table = $wpdb->prefix . BM_TABLE_PREFIX . ‘registry’; $this->audit_table = $wpdb->prefix . BM_TABLE_PREFIX . ‘audit_log’; $this->blockchain_table = $wpdb->prefix . BM_TABLE_PREFIX . ‘blockchain_tx’; } public function add_professional( $data ) { $defaults = [ ‘professional_id’ => $this->generate_professional_id(), ‘status’ => ‘pending’, ‘registered_date’ => current_time( ‘mysql’ ), ‘registered_by’ => get_current_user_id(), ]; $data = wp_parse_args( $data, $defaults ); $result = $this->wpdb->insert( $this->registry_table, $data ); if ( $result ) { $this->log_audit( ‘CREATE_PROFESSIONAL’, $data[‘professional_id’], ‘New professional registered’ ); return $data[‘professional_id’]; } return false; } public function update_professional( $professional_id, $data ) { $result = $this->wpdb->update( $this->registry_table, $data, [ ‘professional_id’ => $professional_id ] ); if ( $result ) { $this->log_audit( ‘UPDATE_PROFESSIONAL’, $professional_id, ‘Professional updated’ ); } return $result; } public function approve_professional( $professional_id, $approver_id ) { $data = [ ‘status’ => ‘active’, ‘approved_by’ => $approver_id, ‘approved_date’ => current_time( ‘mysql’ ), ]; return $this->update_professional( $professional_id, $data ); } public function revoke_professional( $professional_id, $reason ) { $data = [ ‘status’ => ‘revoked’, ‘revocation_reason’ => $reason, ‘revoked_date’ => current_time( ‘mysql’ ), ]; return $this->update_professional( $professional_id, $data ); } public function get_professional( $professional_id ) { return $this->wpdb->get_row( $this->wpdb->prepare( “SELECT * FROM $this->registry_table WHERE professional_id = %s”, $professional_id ) ); } public function get_pending_professionals() { return $this->wpdb->get_results( “SELECT * FROM $this->registry_table WHERE status = ‘pending’ ORDER BY registered_date DESC” ); } public function get_active_professionals( $system = ” ) { $where = “status = ‘active'”; if ( $system ) { $where .= $this->wpdb->prepare( ” AND system = %s”, $system ); } return $this->wpdb->get_results( “SELECT * FROM $this->registry_table WHERE $where ORDER BY approved_date DESC” ); } public function search_professionals( $search_term ) { return $this->wpdb->get_results( $this->wpdb->prepare( “SELECT * FROM $this->registry_table WHERE (professional_id LIKE %s OR full_name LIKE %s OR email LIKE %s) AND status = ‘active'”, “%$search_term%”, “%$search_term%”, “%$search_term%” ) ); } public function get_stats() { $stats = [ ‘total’ => $this->wpdb->get_var( “SELECT COUNT(*) FROM $this->registry_table” ), ‘pending’ => $this->wpdb->get_var( “SELECT COUNT(*) FROM $this->registry_table WHERE status = ‘pending'” ), ‘active’ => $this->wpdb->get_var( “SELECT COUNT(*) FROM $this->registry_table WHERE status = ‘active'” ), ‘revoked’ => $this->wpdb->get_var( “SELECT COUNT(*) FROM $this->registry_table WHERE status = ‘revoked'” ), ‘scb’ => $this->wpdb->get_var( $this->wpdb->prepare( “SELECT COUNT(*) FROM $this->registry_table WHERE system = %s AND status = ‘active'”, ‘SCB’ ) ), ‘kcs_ou’ => $this->wpdb->get_var( $this->wpdb->prepare( “SELECT COUNT(*) FROM $this->registry_table WHERE system = %s AND status = ‘active'”, ‘KCS-OU’ ) ), ‘sca’ => $this->wpdb->get_var( $this->wpdb->prepare( “SELECT COUNT(*) FROM $this->registry_table WHERE system = %s AND status = ‘active'”, ‘SCA’ ) ), ]; return $stats; } private function generate_professional_id() { $prefix = ‘SCB’; $year = date( ‘Y’ ); $random = strtoupper( wp_generate_password( 6, false ) ); return “$prefix-$year-$random”; } public function log_audit( $action, $professional_id, $details ) { $data = [ ‘action’ => $action, ‘professional_id’ => $professional_id, ‘performed_by’ => get_current_user_id(), ‘user_ip’ => $_SERVER[‘REMOTE_ADDR’] ?? ”, ‘details’ => $details, ]; return $this->wpdb->insert( $this->audit_table, $data ); } public function get_audit_log( $limit = 50 ) { return $this->wpdb->get_results( $this->wpdb->prepare( “SELECT * FROM $this->audit_table ORDER BY timestamp DESC LIMIT %d”, $limit ) ); } public function add_blockchain_tx( $professional_id, $tx_hash, $network = ‘polygon’ ) { $data = [ ‘professional_id’ => $professional_id, ‘tx_hash’ => $tx_hash, ‘network’ => $network, ‘created_at’ => current_time( ‘mysql’ ), ]; // Also update the professional record $this->update_professional( $professional_id, [ ‘tx_hash’ => $tx_hash, ‘blockchain_network’ => $network, ] ); return $this->wpdb->insert( $this->blockchain_table, $data ); } public function get_blockchain_txs( $limit = 20 ) { return $this->wpdb->get_results( $this->wpdb->prepare( “SELECT * FROM $this->blockchain_table ORDER BY created_at DESC LIMIT %d”, $limit ) ); } } “` ### **Enhanced Admin Class with Complete UI:** “`php db = BM_Database::get_instance(); add_action( ‘admin_menu’, [ $this, ‘register_menu’ ] ); add_action( ‘admin_enqueue_scripts’, [ $this, ‘enqueue_assets’ ] ); add_action( ‘admin_init’, [ $this, ‘handle_actions’ ] ); add_action( ‘wp_ajax_bm_approve_professional’, [ $this, ‘ajax_approve_professional’ ] ); add_action( ‘wp_ajax_bm_revoke_professional’, [ $this, ‘ajax_revoke_professional’ ] ); } public function register_menu() { add_menu_page( ‘Barista Mtaani’, ‘Barista Mtaani’, ‘manage_bm_registry’, ‘barista-mtaani’, [ $this, ‘dashboard_page’ ], ‘dashicons-coffee’, 26 ); add_submenu_page( ‘barista-mtaani’, ‘Dashboard’, ‘Dashboard’, ‘manage_bm_registry’, ‘barista-mtaani’, [ $this, ‘dashboard_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Add Professional’, ‘Add Professional’, ‘manage_bm_registry’, ‘barista-mtaani-add’, [ $this, ‘add_professional_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Pending Approval’, ‘Pending Approval’, ‘manage_bm_approvals’, ‘barista-mtaani-pending’, [ $this, ‘pending_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Professional Registry’, ‘Registry’, ‘manage_bm_registry’, ‘barista-mtaani-registry’, [ $this, ‘registry_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Revoked Credentials’, ‘Revoked’, ‘manage_bm_approvals’, ‘barista-mtaani-revoked’, [ $this, ‘revoked_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Audit Log’, ‘Audit Log’, ‘manage_bm_approvals’, ‘barista-mtaani-audit’, [ $this, ‘audit_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Blockchain’, ‘Blockchain’, ‘manage_bm_settings’, ‘barista-mtaani-blockchain’, [ $this, ‘blockchain_page’ ] ); add_submenu_page( ‘barista-mtaani’, ‘Settings’, ‘Settings’, ‘manage_bm_settings’, ‘barista-mtaani-settings’, [ $this, ‘settings_page’ ] ); } public function enqueue_assets( $hook ) { if ( strpos( $hook, ‘barista-mtaani’ ) === false ) { return; } wp_enqueue_style( ‘bm-admin-css’, BM_PLUGIN_URL . ‘assets/css/admin.css’, [], BM_VERSION ); wp_enqueue_script( ‘bm-admin-js’, BM_PLUGIN_URL . ‘assets/js/admin.js’, [ ‘jquery’, ‘wp-util’ ], BM_VERSION, true ); wp_localize_script( ‘bm-admin-js’, ‘bm_ajax’, [ ‘ajax_url’ => admin_url( ‘admin-ajax.php’ ), ‘nonce’ => wp_create_nonce( ‘bm_admin_nonce’ ), ]); } public function dashboard_page() { $stats = $this->db->get_stats(); $recent = $this->db->get_active_professionals(); $recent = array_slice( $recent, 0, 5 ); include BM_PLUGIN_DIR . ‘templates/admin/dashboard.php’; } public function add_professional_page() { if ( $_SERVER[‘REQUEST_METHOD’] === ‘POST’ && isset( $_POST[‘bm_add_professional’] ) ) { $this->handle_add_professional(); } include BM_PLUGIN_DIR . ‘templates/admin/add-professional.php’; } public function pending_page() { $pending = $this->db->get_pending_professionals(); include BM_PLUGIN_DIR . ‘templates/admin/pending.php’; } public function registry_page() { $system = isset( $_GET[‘system’] ) ? sanitize_text_field( $_GET[‘system’] ) : ”; $professionals = $this->db->get_active_professionals( $system ); include BM_PLUGIN_DIR . ‘templates/admin/registry.php’; } public function revoked_page() { $revoked = $this->db->get_active_professionals(); // Need to filter for revoked include BM_PLUGIN_DIR . ‘templates/admin/revoked.php’; } public function audit_page() { $audit_log = $this->db->get_audit_log(); include BM_PLUGIN_DIR . ‘templates/admin/audit.php’; } public function blockchain_page() { $txs = $this->db->get_blockchain_txs(); include BM_PLUGIN_DIR . ‘templates/admin/blockchain.php’; } public function settings_page() { include BM_PLUGIN_DIR . ‘templates/admin/settings.php’; } private function handle_add_professional() { $data = [ ‘full_name’ => sanitize_text_field( $_POST[‘full_name’] ), ’email’ => sanitize_email( $_POST[’email’] ), ‘phone’ => sanitize_text_field( $_POST[‘phone’] ), ‘system’ => sanitize_text_field( $_POST[‘system’] ), ‘credential’ => sanitize_text_field( $_POST[‘credential’] ), ‘level’ => sanitize_text_field( $_POST[‘level’] ), ‘issue_date’ => sanitize_text_field( $_POST[‘issue_date’] ), ‘expiry_date’ => sanitize_text_field( $_POST[‘expiry_date’] ), ‘badge_type’ => sanitize_text_field( $_POST[‘badge_type’] ), ]; $professional_id = $this->db->add_professional( $data ); if ( $professional_id ) { wp_redirect( admin_url( ‘admin.php?page=barista-mtaani-pending&added=’ . $professional_id ) ); exit; } } public function ajax_approve_professional() { check_ajax_referer( ‘bm_admin_nonce’, ‘nonce’ ); $professional_id = sanitize_text_field( $_POST[‘professional_id’] ); $result = $this->db->approve_professional( $professional_id, get_current_user_id() ); if ( $result ) { wp_send_json_success( [ ‘message’ => ‘Professional approved successfully!’ ] ); } else { wp_send_json_error( [ ‘message’ => ‘Failed to approve professional.’ ] ); } } public function ajax_revoke_professional() { check_ajax_referer( ‘bm_admin_nonce’, ‘nonce’ ); $professional_id = sanitize_text_field( $_POST[‘professional_id’] ); $reason = sanitize_text_field( $_POST[‘reason’] ); $result = $this->db->revoke_professional( $professional_id, $reason ); if ( $result ) { wp_send_json_success( [ ‘message’ => ‘Professional revoked successfully!’ ] ); } else { wp_send_json_error( [ ‘message’ => ‘Failed to revoke professional.’ ] ); } } private function handle_actions() { if ( ! isset( $_GET[‘page’] ) || strpos( $_GET[‘page’], ‘barista-mtaani’ ) === false ) { return; } // Handle bulk actions if ( isset( $_POST[‘bm_bulk_action’] ) && isset( $_POST[‘bm_professionals’] ) ) { $this->handle_bulk_actions(); } } private function handle_bulk_actions() { $action = sanitize_text_field( $_POST[‘bm_bulk_action’] ); $professionals = array_map( ‘sanitize_text_field’, $_POST[‘bm_professionals’] ); foreach ( $professionals as $professional_id ) { switch ( $action ) { case ‘approve’: $this->db->approve_professional( $professional_id, get_current_user_id() ); break; case ‘revoke’: $this->db->revoke_professional( $professional_id, ‘Bulk revocation’ ); break; } } wp_redirect( add_query_arg( ‘bulk_updated’, count( $professionals ), wp_get_referer() ) ); exit; } } “` ### **Public & Shortcodes Classes:** “`php db = BM_Database::get_instance(); add_action( ‘wp_enqueue_scripts’, [ $this, ‘enqueue_public_assets’ ] ); } public function enqueue_public_assets() { if ( is_page( get_option( ‘bm_verify_page_id’ ) ) || is_page( get_option( ‘bm_registry_page_id’ ) ) ) { wp_enqueue_style( ‘bm-public-css’, BM_PLUGIN_URL . ‘assets/css/public.css’, [], BM_VERSION ); wp_enqueue_script( ‘bm-public-js’, BM_PLUGIN_URL . ‘assets/js/public.js’, [ ‘jquery’ ], BM_VERSION, true ); } } } // includes/class-bm-shortcodes.php if ( ! defined( ‘ABSPATH’ ) ) exit; class BM_Shortcodes { private $db; public function __construct() { $this->db = BM_Database::get_instance(); add_shortcode( ‘bm_verify_credential’, [ $this, ‘verify_credential_shortcode’ ] ); add_shortcode( ‘bm_public_registry’, [ $this, ‘public_registry_shortcode’ ] ); add_shortcode( ‘bm_professional_badge’, [ $this, ‘professional_badge_shortcode’ ] ); } public function verify_credential_shortcode() { ob_start(); $professional_id = isset( $_GET[‘id’] ) ? sanitize_text_field( $_GET[‘id’] ) : ”; if ( $professional_id ) { $professional = $this->db->get_professional( $professional_id ); include BM_PLUGIN_DIR . ‘templates/public/verify-result.php’; } else { include BM_PLUGIN_DIR . ‘templates/public/verify-form.php’; } return ob_get_clean(); } public function public_registry_shortcode() { ob_start(); $search = isset( $_GET[‘search’] ) ? sanitize_text_field( $_GET[‘search’] ) : ”; $system = isset( $_GET[‘system’] ) ? sanitize_text_field( $_GET[‘system’] ) : ”; if ( $search ) { $professionals = $this->db->search_professionals( $search ); } else { $professionals = $this->db->get_active_professionals( $system ); } include BM_PLUGIN_DIR . ‘templates/public/registry.php’; return ob_get_clean(); } public function professional_badge_shortcode( $atts ) { $atts = shortcode_atts( [ ‘id’ => ”, ‘size’ => ‘medium’, ‘show_qr’ => ‘yes’, ], $atts, ‘bm_professional_badge’ ); if ( ! $atts[‘id’] ) { return ‘

Please provide a professional ID

‘; } $professional = $this->db->get_professional( $atts[‘id’] ); if ( ! $professional ) { return ‘

Professional not found

‘; } ob_start(); include BM_PLUGIN_DIR . ‘templates/public/badge.php’; return ob_get_clean(); } } // includes/class-bm-api.php if ( ! defined( ‘ABSPATH’ ) ) exit; class BM_API { private $db; public function __construct() { $this->db = BM_Database::get_instance(); add_action( ‘rest_api_init’, [ $this, ‘register_routes’ ] ); } public function register_routes() { register_rest_route( ‘barista-mtaani/v1’, ‘/verify/(?P[a-zA-Z0-9\-]+)’, [ ‘methods’ => ‘GET’, ‘callback’ => [ $this, ‘verify_credential’ ], ‘permission_callback’ => ‘__return_true’, ] ); register_rest_route( ‘barista-mtaani/v1’, ‘/registry’, [ ‘methods’ => ‘GET’, ‘callback’ => [ $this, ‘get_registry’ ], ‘permission_callback’ => ‘__return_true’, ] ); register_rest_route( ‘barista-mtaani/v1’, ‘/stats’, [ ‘methods’ => ‘GET’, ‘callback’ => [ $this, ‘get_stats’ ], ‘permission_callback’ => ‘__return_true’, ] ); } public function verify_credential( $request ) { $id = $request[‘id’]; $professional = $this->db->get_professional( $id ); if ( ! $professional ) { return new WP_Error( ‘not_found’, ‘Credential not found’, [ ‘status’ => 404 ] ); } return rest_ensure_response( [ ‘id’ => $professional->professional_id, ‘name’ => $professional->full_name, ‘credential’ => $professional->credential, ‘system’ => $professional->system, ‘level’ => $professional->level, ‘status’ => $professional->status, ‘issue_date’ => $professional->issue_date, ‘blockchain_verified’ => ! empty( $professional->tx_hash ), ] ); } public function get_registry( $request ) { $system = $request->get_param( ‘system’ ); $professionals = $this->db->get_active_professionals( $system ); $data = array_map( function( $pro ) { return [ ‘id’ => $pro->professional_id, ‘name’ => $pro->full_name, ‘credential’ => $pro->credential, ‘system’ => $pro->system, ‘level’ => $pro->level, ‘issue_date’ => $pro->issue_date, ]; }, $professionals ); return rest_ensure_response( $data ); } public function get_stats() { $stats = $this->db->get_stats(); return rest_ensure_response( $stats ); } } “` ### **Create Template Files:** Create these template files in a `templates/` directory: **templates/admin/dashboard.php** “`php

☕ Barista Mtaani Dashboard

Total Professionals

Pending Approval

Active Credentials

SCB Professionals

Recent Approvals

IDNameCredentialSystemApproved
professional_id; ?>full_name; ?>credential; ?>

Barista Mtaani

Professional Credential Verification

Awarded to: full_name ); ?>

Credential ID:

professional_id ); ?>

System:

system ); ?>

Issued:

issue_date ) ); ?>

Level:

level ); ?>

tx_hash ): ?>

Blockchain Verified

Scan QR code to verify

Credential Not Found

The credential ID “” was not found in our registry.

Try Another ID
“` ### **Enhanced Admin CSS:** “`css /* assets/css/admin.css */ .bm-dashboard-cards { display
KENYA COFFEE SCHOOL SKILLS CERTIFICATE / DIPLOMA
#Powered by GoLearn
Kenya Coffee School



@kenyacoffeeschool
BCSTTI

  • TikTok
  • Instagram
  • Mail
  • Facebook

Copyright 2025 ©Kenya Coffee School ©Golearn ©Lavazza Coffee Center ©Specialty Coffee Academies ©Specialty Coffee Barista ©Open Skills Education ©Barista Mtaani
  • Home
  • Kenya coffee school – the best barista and specialty coffee school
  • KCS Info Hub
  • About KCS
  • Projects
  • Barista Mtaani Project
  • Barista Mtaani Project
  • Certifications
  • KCS Education
  • Shop at Kenya Coffee School
  • Why Train at Kenya Coffee School
  • Kenya Coffee Association: Brewing a Future Beyond the Cup
  • 2025 to 2030 KCS Courses and Programs
  • KCS Research Projects
  • Mixology & Bartender Courses
  • News and Events Blog
  • Official Disclaimer — Kenya Coffee School
  • Transforming the Coffee Value Chain for Women and Youth
  • Kenya Coffee School App Download
Kenya Coffee School Barista School at GoLearn

We are using cookies to give you the best experience on our website.

You can find out more about which cookies we are using or switch them off in .

Kenya Coffee School
Powered by  GDPR Cookie Compliance
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Strictly Necessary Cookies

Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.