SlideShare a Scribd company logo
Implementing Sport
Leaderboards with a
WordPress Plugin
About GrIFK
▪ IFK Grankulla (GrIFK) is a proud
local hockey program in the town
of Kauniainen, Finland. Kauniainen
with 9,395 inhabitants is located in
the Helsinki metro area.
▪ 741 hockey players play for GrIFK.
About Myself
▪ CEO and founder of Exove
▪ Team leader of GrIFK 05 team
▪ Hockey referee
▪ WordPress developer since 2004
GrIFK 05
48 players born in 2005
Grani On Ice
▪ Grani On Ice is an annual junior ice hockey
tournament
▪ Organised by each team, one or two days in
April & May
▪ 2016-2017 season, six tournaments on seven days
▪ Biggest source of income for the teams
Grani on Ice & WordPress
▪ I’ve been responsible for the sites for 05 and
07 teams, as I have children on those teams
▪ Implemented them with WordPress to keep
things simple and maintainable
▪ WordPress did not have any good sports
leaderboard plugins, so I decided to wrote my
own
Leaderboards
▪ Program - matches with teams, times, and location
▪ Game results with goals
▪ Ranking with divisions, semifinals, and finals
▪ Top scorers, top goals, and top assists
▪ Top saves for goaltenders
▪ Player lists for each team
Data Model
Team
Player
Goal Save
Game
Tied to a division, contains
information about serie
Intermissions
Breaks between games
Variations
▪ Tournaments have different scoring systems
▪ Depends on number of teams, whether game is
played on full or half ice, etc.
▪ Also, all statistics are not gathered for
younger players (goalie saves)
▪ It was also decided not to collect penalties or
on-ice statistics (fair play, +/- saldo)
THE SOLUTION
Core Plugin Concepts
▪ Plugin provides admin interfaces for
▪ Managing player, team, etc. data for admins
▪ Adding and modifying game results for editors
▪ Leaderboards are created using shortcodes
▪ Can be inserted into normal pages and content can
be added around them
Technical Considerations
▪ Each admin interface page and shortcode has its own
function
▪ Admin functions use simple helper function to generate data tables
▪ Helper functions for frequently used actions
▪ Number of different sort routines to order the results of the
leaderboards
▪ Plugin generates HTML in shortcodes
▪ Styled inside theme CSS (or similar)
Initialisation
▪ Configuration is red from a separate PHP file
▪ Tournament specific data isolated into that file
▪ Two actions registered for admin menu and
enqueuing JavaScript
▪ Eight shortcodes added to support all
leaderboards
On Code Level
register_activation_hook(__FILE__, 'gtInstall');
add_action('admin_menu', 'gtMenu');
add_action('wp_enqueue_scripts', 'gtScripts');
add_shortcode('gt_standings', 'gtShowStandings');
add_shortcode('gt_matches', 'gtShowMatches');
add_shortcode('gt_program', 'gtShowProgram');
add_shortcode('gt_goals', 'gtShowGoals');
add_shortcode('gt_saves', 'gtShowSaves');
add_shortcode('gt_current', 'gtShowCurrent');
add_shortcode('gt_players', 'gtShowPlayers');
add_shortcode('gt_shots', 'gtShowShots');
Admin Interfaces
▪ Admin interfaces are either tables showing
data or forms used to add or edit data
▪ Tables are generated inside admin page
function
▪ Forms are created using a helper function
On Code Level
// Admin table generation for team listing
echo '<table class="wp-list-table
widefat"><thead><tr><th>Name</th><th>Division</th><th>Position</th><th>Sweepstake</
th><th>Actions</th></tr></thead><tbody>';
$i = 0;
foreach($dt['teams'] as $t) {
echo '<tr', (($i++) % 2 == 0 ? ' class="alternate"' : ''), '><td>', $t['name'],
'</td><td>', $t['division'], '</td><td>', $t['position'], '</td><td>',
$t['sweepstake'], '</td><td><a href="', $currentUrl, '&edit=', $t['id'],
'">Edit</a> | <a href="', $currentUrl, '&remove=', $t['id'],
'">Remove</a></td></tr>';
}
echo '</tbody></table>';
On Code Level
// Form generation for adding and editing teams
$teamData = array('id' => '', 'name' => '', 'division' => '', 'position' => '',
'sweepstake' => '', 'submit' => 'Add');
if($editTeam) {
$teamData = array('id' => $editTeam['id'], 'name' => $editTeam['name'],
'division' => $editTeam['division'],
'position' => $editTeam['position'],
'sweepstake' => $editTeam['sweepstake'],
'submit' => 'Modify');
}
$teamForm = array(array('name' => 'id',
'type' => 'hidden',
'value' => $teamData['id']),
[...]
On Code Level
if(!$editTeam) {
echo '<h3>Add Team</h3>';
}
echo '<form action="" method="post"><input type="hidden" name="page"
value="gtTournamentTeams">';
gtFormTable($teamForm);
echo '</form>';
if($editTeam) {
echo '<p><a href="', $_SERVER['PHP_SELF'], '?page=gtTournamentTeams">Back to
Teams</a></p></div>';
}
Admin Rights
▪ Two different user levels
▪ Admin users can manage everything
▪ Editors can input goals, saves, and manage game
starts + ends
▪ Handled by showing extra menu items based
on user rights
On Code Level
function gtMenu() {
add_menu_page('Grani Tournament', 'Tournament', 'edit_posts', 'gtTournament',
'gtEnterScores');
add_submenu_page('gtTournament', 'Grani Tournament Teams', 'Manage Teams',
'install_plugins', 'gtTournamentTeams', 'gtModifyTeams');
add_submenu_page('gtTournament', 'Grani Tournament Players', 'Manage Players',
'install_plugins', 'gtTournamentPlayers', 'gtModifyPlayers');
add_submenu_page('gtTournament', 'Grani Tournament Games', 'Manage Games',
'install_plugins', 'gtTournamentGames', 'gtModifyGames');
add_submenu_page('gtTournament', 'Grani Tournament Intermissions', 'Manage
Intermissions', 'install_plugins', 'gtTournamentIntermissions',
'gtModifyIntermissions');
add_menu_page('Slap Shots', 'Slap shots', 'edit_posts', 'gtTournamentShots',
'gtEnterShots');
}
Leaderboard Calculation
▪ The leaderboards are not stored into the
database, but calculated on the fly
▪ One function reads data from the database
and calculates game scores, team points and
positions
▪ The amount of data read and calculations made
depend on the parameters - four steps in total
On Code Level
function gtReadData($players = false, $games = false, $intermissions = false,
$saves = false) {
global $wpdb;
global $gtParams;
$ret = array();
$teamRows = $wpdb->get_results("SELECT id, name, division, position,
sweepstake FROM ${gtParams['teamTable']}
ORDER BY division, position, name");
$ret['teams'] = array();
$teamDivPos = array();
On Code Level
foreach($teamRows as $r) {
$t = array();
$t['id'] = $r->id;
$t['name'] = $r->name;
$t['position'] = $r->position;
$t['division'] = $r->division;
$t['sweepstake'] = $r->sweepstake;
$ret['teams']['' . $r->id] = $t;
$teamDivPos[$r->division . 'T' . $r->position] = $r->id;
}
On Code Level
if($players) {
$playerRows = $wpdb->get_results("SELECT id, team, number, name
FROM $gtParams['playerTable']}
ORDER BY team, number, name");
$ret['players'] = array();
foreach($playerRows as $r) {
$p = array();
$p['id'] = $r->id;
$p['team'] = $r->team;
$p['name'] = $r->name;
$p['number'] = $r->number;
$ret['players']['' . $r->id] = $p;
}
}
Leaderboard Display
▪ The shortcode functions request calculated
data
▪ The data contains all information required for
the leaderboard display
▪ The actual leaderboard generation is a
simple foreach() loop
▪ With ugly HTML generation inside
On Code Level
// Snippet from showing goalie saves
foreach($totalsByPlayer as $k => $v) {
$ratio = number_format($v['ratio'] * 100, 1);
if($ratio != $prevRatio) {
$pos += $inc;
$inc = 1;
$prevRatio = $ratio;
}
else {
$inc++;
}
On Code Level
$ret .= '<tr class="gtToggler ' . ($i % 2 == 0 ? 'odd' : 'even') . '"
id="gtSavesPlayer_' . $k . '"><td>' . $pos . '.</td><td colspan="2">' .
$dt['players'][$k]['name'] . ' (' . $dt['players'][$k]['number'] . ')</td><td
class="gtTogglerCue">' . $dt['teams'][$dt['players'][$k]['team']]['name'] .
($gtParams['useLevels'] ? ' &#8210; ' . str_repeat('A',
($dt['teams'][$dt['players'][$k]['team']]['division']{0})) : '') .
'</td><td class="align-right">' . $v['saves'] . '</td><td class="align-right">' .
$v['goals'] . '</td><td class="align-right">' . $ratio . '%</td></tr>';
On Code Level
foreach($dt['games'] as $gk => $gv) {
if(isset($gamesByPlayer[$k][$gk])) {
$g = $gamesByPlayer[$k][$gk];
$tot = $g['saves'] + $g['goals'];
$ret .= '<tr class="gtToggled gtSavesPlayer_' . $k . '_games"><td>' .
substr($gv['time'], 0, 5) . '</td><td>' . $dt['teams'][$gv['home']]['name'] .
'</td><td>&nbsp;vs&nbsp;</td><td>' . $dt['teams'][$gv['away']]['name'] . '</td><td
class="align-right">' . $g['saves'] . '</td><td class="align-right">' . $g['goals']
. '</td><td class="align-right">' . ($tot > 0 ? number_format($g['saves'] * 100 /
($g['saves'] + $g['goals']), 1) : '-') . '%</td></tr>';
}
}
$i++;
}
Digital Signage Support
▪ Certain leaderboards can be shown on big
displays
▪ The system rotates leaderboards and ads
using JavaScript
▪ The leaderboards scroll
DS Implementation
▪ A couple of jQuery functions that
▪ Remove redundant items from the page
▪ Increase font sizes
▪ Scroll leaderboards
▪ Change pages with fade effect
On Code Level
if(window.location.search == '?leaderboard') {
$('#header').hide();
$('#widgets').hide();
$('.post-edit').hide();
$('#footer').hide();
$('.tournamentLinks').hide();
$('#content').removeClass('col-620').addClass('col-940')
.css('font-size', '250%').css('line-height', '1.5em')
.css('margin-bottom', '0');
$('#container').css('max-width', '90%');
$('.gtTogglerCue').removeClass('gtTogglerCue');
[...]
On Code Level
if($('#fullscreenad').length > 0) {
setTimeout(function() {
loader();
}, 18000);
}
else {
var speed = 0.05;
var distance = $("#wrapper").height() - $(window).height() +
$("#wrapper").offset().top + 50;
var animationTime = distance / speed;
On Code Level
if(animationTime < 0) {
animationTime = 0;
}
if($(window).height() < $(document).height() && animationTime > 0){
$('#container').css('overflow', 'hidden')
.height($(window).height() - 0);
setTimeout(function() {
$('#wrapper').animate({ marginTop: -distance },
animationTime, 'linear');
}, 5000);
Way Forward
▪ No new requirements on the horizon
▪ Handles all major needs for GrIFK
tournaments
▪ Maybe new tournament models needed
To Public Plugin?
▪ Would require a lot of extra work that adds no value to
GrIFK tournaments
▪ More tournament models required -> calculation would
be more generic and thus complex
▪ Admin interfaces should be made prettier
▪ Input validation needed
THANK YOU!
ANY QUESTIONS?

More Related Content

Similar to WordPress Café November - Sport Leaderboards with a Plugin

David Kopal - Write better React with ReasonML - Codemotion Milan 2018
David Kopal - Write better React with ReasonML - Codemotion Milan 2018David Kopal - Write better React with ReasonML - Codemotion Milan 2018
David Kopal - Write better React with ReasonML - Codemotion Milan 2018
Codemotion
 
Opensocial Codelab
Opensocial CodelabOpensocial Codelab
Opensocial Codelab
Pieter De Schepper
 
De CRUD à DDD pas à pas
De CRUD à DDD pas à pasDe CRUD à DDD pas à pas
De CRUD à DDD pas à pas
Charles Desneuf
 
Building a good quality WordPress theme
Building a good quality WordPress themeBuilding a good quality WordPress theme
Building a good quality WordPress theme
Nisha Singh
 
View source epaper.sakshi
View source epaper.sakshiView source epaper.sakshi
View source epaper.sakshiDiwakara Reddy
 
Code Management
Code ManagementCode Management
Code Management
Y. Thong Kuah
 
Digital analytics with R - Sydney Users of R Forum - May 2015
Digital analytics with R - Sydney Users of R Forum - May 2015Digital analytics with R - Sydney Users of R Forum - May 2015
Digital analytics with R - Sydney Users of R Forum - May 2015
Johann de Boer
 
Stacki and Chef at Pardot
Stacki and Chef at PardotStacki and Chef at Pardot
Stacki and Chef at Pardot
Salesforce Engineering
 
PlayFab Advanced Cloud Script
PlayFab Advanced Cloud ScriptPlayFab Advanced Cloud Script
PlayFab Advanced Cloud Script
Thomas Robbins
 
New Tools for a More Functional C++
New Tools for a More Functional C++New Tools for a More Functional C++
New Tools for a More Functional C++
Sumant Tambe
 
Private slideshow
Private slideshowPrivate slideshow
Private slideshowsblackman
 
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
cehwitham
 
Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application Framework
Dirk Haun
 
Pengenalan AngularJS
Pengenalan AngularJSPengenalan AngularJS
Pengenalan AngularJS
Edi Santoso
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
Pierre MARTIN
 
Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008
Rob
 

Similar to WordPress Café November - Sport Leaderboards with a Plugin (20)

Introduction to angular js
Introduction to angular jsIntroduction to angular js
Introduction to angular js
 
David Kopal - Write better React with ReasonML - Codemotion Milan 2018
David Kopal - Write better React with ReasonML - Codemotion Milan 2018David Kopal - Write better React with ReasonML - Codemotion Milan 2018
David Kopal - Write better React with ReasonML - Codemotion Milan 2018
 
Opensocial Codelab
Opensocial CodelabOpensocial Codelab
Opensocial Codelab
 
De CRUD à DDD pas à pas
De CRUD à DDD pas à pasDe CRUD à DDD pas à pas
De CRUD à DDD pas à pas
 
Introduction to AngularJS
Introduction to AngularJSIntroduction to AngularJS
Introduction to AngularJS
 
Building a good quality WordPress theme
Building a good quality WordPress themeBuilding a good quality WordPress theme
Building a good quality WordPress theme
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
View source epaper.sakshi
View source epaper.sakshiView source epaper.sakshi
View source epaper.sakshi
 
Code Management
Code ManagementCode Management
Code Management
 
Digital analytics with R - Sydney Users of R Forum - May 2015
Digital analytics with R - Sydney Users of R Forum - May 2015Digital analytics with R - Sydney Users of R Forum - May 2015
Digital analytics with R - Sydney Users of R Forum - May 2015
 
Stacki and Chef at Pardot
Stacki and Chef at PardotStacki and Chef at Pardot
Stacki and Chef at Pardot
 
PlayFab Advanced Cloud Script
PlayFab Advanced Cloud ScriptPlayFab Advanced Cloud Script
PlayFab Advanced Cloud Script
 
New Tools for a More Functional C++
New Tools for a More Functional C++New Tools for a More Functional C++
New Tools for a More Functional C++
 
Private slideshow
Private slideshowPrivate slideshow
Private slideshow
 
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
Making WordPress Your CMS and Automatically Updating a Self Hosted WordPress ...
 
Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application Framework
 
Pengenalan AngularJS
Pengenalan AngularJSPengenalan AngularJS
Pengenalan AngularJS
 
20110820 header new style
20110820 header new style20110820 header new style
20110820 header new style
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 
Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008
 

More from Exove

Data security in the age of GDPR – most common data security problems
Data security in the age of GDPR – most common data security problemsData security in the age of GDPR – most common data security problems
Data security in the age of GDPR – most common data security problems
Exove
 
Provisioning infrastructure to AWS using Terraform – Exove
Provisioning infrastructure to AWS using Terraform – ExoveProvisioning infrastructure to AWS using Terraform – Exove
Provisioning infrastructure to AWS using Terraform – Exove
Exove
 
Advanced custom fields in Wordpress
Advanced custom fields in WordpressAdvanced custom fields in Wordpress
Advanced custom fields in Wordpress
Exove
 
Introduction to Robot Framework – Exove
Introduction to Robot Framework – ExoveIntroduction to Robot Framework – Exove
Introduction to Robot Framework – Exove
Exove
 
Jenkins and visual regression – Exove
Jenkins and visual regression – ExoveJenkins and visual regression – Exove
Jenkins and visual regression – Exove
Exove
 
Server-side React with Headless CMS – Exove
Server-side React with Headless CMS – ExoveServer-side React with Headless CMS – Exove
Server-side React with Headless CMS – Exove
Exove
 
WebSockets in Bravo Dashboard – Exove
WebSockets in Bravo Dashboard – ExoveWebSockets in Bravo Dashboard – Exove
WebSockets in Bravo Dashboard – Exove
Exove
 
Diversity in recruitment
Diversity in recruitmentDiversity in recruitment
Diversity in recruitment
Exove
 
Saavutettavuus liiketoimintana
Saavutettavuus liiketoimintanaSaavutettavuus liiketoimintana
Saavutettavuus liiketoimintana
Exove
 
Saavutettavuus osana Eläkeliiton verkkosivu-uudistusta
Saavutettavuus osana Eläkeliiton verkkosivu-uudistustaSaavutettavuus osana Eläkeliiton verkkosivu-uudistusta
Saavutettavuus osana Eläkeliiton verkkosivu-uudistusta
Exove
 
Mitä saavutettavuusdirektiivi pitää sisällään
Mitä saavutettavuusdirektiivi pitää sisälläänMitä saavutettavuusdirektiivi pitää sisällään
Mitä saavutettavuusdirektiivi pitää sisällään
Exove
 
Creating Landing Pages for Drupal 8
Creating Landing Pages for Drupal 8Creating Landing Pages for Drupal 8
Creating Landing Pages for Drupal 8
Exove
 
GDPR for developers
GDPR for developersGDPR for developers
GDPR for developers
Exove
 
Managing Complexity and Privacy Debt with Drupal
Managing Complexity and Privacy Debt with DrupalManaging Complexity and Privacy Debt with Drupal
Managing Complexity and Privacy Debt with Drupal
Exove
 
Life with digital services after GDPR
Life with digital services after GDPRLife with digital services after GDPR
Life with digital services after GDPR
Exove
 
GDPR - no beginning no end
GDPR - no beginning no endGDPR - no beginning no end
GDPR - no beginning no end
Exove
 
Developing truly personalised experiences
Developing truly personalised experiencesDeveloping truly personalised experiences
Developing truly personalised experiences
Exove
 
Customer Experience and Personalisation
Customer Experience and PersonalisationCustomer Experience and Personalisation
Customer Experience and Personalisation
Exove
 
Adventures In Programmatic Branding – How To Design With Algorithms And How T...
Adventures In Programmatic Branding – How To Design With Algorithms And How T...Adventures In Programmatic Branding – How To Design With Algorithms And How T...
Adventures In Programmatic Branding – How To Design With Algorithms And How T...
Exove
 
Dataohjattu asiakaskokemus
Dataohjattu asiakaskokemusDataohjattu asiakaskokemus
Dataohjattu asiakaskokemus
Exove
 

More from Exove (20)

Data security in the age of GDPR – most common data security problems
Data security in the age of GDPR – most common data security problemsData security in the age of GDPR – most common data security problems
Data security in the age of GDPR – most common data security problems
 
Provisioning infrastructure to AWS using Terraform – Exove
Provisioning infrastructure to AWS using Terraform – ExoveProvisioning infrastructure to AWS using Terraform – Exove
Provisioning infrastructure to AWS using Terraform – Exove
 
Advanced custom fields in Wordpress
Advanced custom fields in WordpressAdvanced custom fields in Wordpress
Advanced custom fields in Wordpress
 
Introduction to Robot Framework – Exove
Introduction to Robot Framework – ExoveIntroduction to Robot Framework – Exove
Introduction to Robot Framework – Exove
 
Jenkins and visual regression – Exove
Jenkins and visual regression – ExoveJenkins and visual regression – Exove
Jenkins and visual regression – Exove
 
Server-side React with Headless CMS – Exove
Server-side React with Headless CMS – ExoveServer-side React with Headless CMS – Exove
Server-side React with Headless CMS – Exove
 
WebSockets in Bravo Dashboard – Exove
WebSockets in Bravo Dashboard – ExoveWebSockets in Bravo Dashboard – Exove
WebSockets in Bravo Dashboard – Exove
 
Diversity in recruitment
Diversity in recruitmentDiversity in recruitment
Diversity in recruitment
 
Saavutettavuus liiketoimintana
Saavutettavuus liiketoimintanaSaavutettavuus liiketoimintana
Saavutettavuus liiketoimintana
 
Saavutettavuus osana Eläkeliiton verkkosivu-uudistusta
Saavutettavuus osana Eläkeliiton verkkosivu-uudistustaSaavutettavuus osana Eläkeliiton verkkosivu-uudistusta
Saavutettavuus osana Eläkeliiton verkkosivu-uudistusta
 
Mitä saavutettavuusdirektiivi pitää sisällään
Mitä saavutettavuusdirektiivi pitää sisälläänMitä saavutettavuusdirektiivi pitää sisällään
Mitä saavutettavuusdirektiivi pitää sisällään
 
Creating Landing Pages for Drupal 8
Creating Landing Pages for Drupal 8Creating Landing Pages for Drupal 8
Creating Landing Pages for Drupal 8
 
GDPR for developers
GDPR for developersGDPR for developers
GDPR for developers
 
Managing Complexity and Privacy Debt with Drupal
Managing Complexity and Privacy Debt with DrupalManaging Complexity and Privacy Debt with Drupal
Managing Complexity and Privacy Debt with Drupal
 
Life with digital services after GDPR
Life with digital services after GDPRLife with digital services after GDPR
Life with digital services after GDPR
 
GDPR - no beginning no end
GDPR - no beginning no endGDPR - no beginning no end
GDPR - no beginning no end
 
Developing truly personalised experiences
Developing truly personalised experiencesDeveloping truly personalised experiences
Developing truly personalised experiences
 
Customer Experience and Personalisation
Customer Experience and PersonalisationCustomer Experience and Personalisation
Customer Experience and Personalisation
 
Adventures In Programmatic Branding – How To Design With Algorithms And How T...
Adventures In Programmatic Branding – How To Design With Algorithms And How T...Adventures In Programmatic Branding – How To Design With Algorithms And How T...
Adventures In Programmatic Branding – How To Design With Algorithms And How T...
 
Dataohjattu asiakaskokemus
Dataohjattu asiakaskokemusDataohjattu asiakaskokemus
Dataohjattu asiakaskokemus
 

Recently uploaded

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
Ralf Eggert
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
OnBoard
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Nexer Digital
 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
nkrafacyberclub
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
mikeeftimakis1
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 

Recently uploaded (20)

FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)PHP Frameworks: I want to break free (IPC Berlin 2024)
PHP Frameworks: I want to break free (IPC Berlin 2024)
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Leading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdfLeading Change strategies and insights for effective change management pdf 1.pdf
Leading Change strategies and insights for effective change management pdf 1.pdf
 
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
 
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptxSecstrike : Reverse Engineering & Pwnable tools for CTF.pptx
Secstrike : Reverse Engineering & Pwnable tools for CTF.pptx
 
Introduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - CybersecurityIntroduction to CHERI technology - Cybersecurity
Introduction to CHERI technology - Cybersecurity
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 

WordPress Café November - Sport Leaderboards with a Plugin

  • 2. About GrIFK ▪ IFK Grankulla (GrIFK) is a proud local hockey program in the town of Kauniainen, Finland. Kauniainen with 9,395 inhabitants is located in the Helsinki metro area. ▪ 741 hockey players play for GrIFK.
  • 3. About Myself ▪ CEO and founder of Exove ▪ Team leader of GrIFK 05 team ▪ Hockey referee ▪ WordPress developer since 2004
  • 4. GrIFK 05 48 players born in 2005
  • 5. Grani On Ice ▪ Grani On Ice is an annual junior ice hockey tournament ▪ Organised by each team, one or two days in April & May ▪ 2016-2017 season, six tournaments on seven days ▪ Biggest source of income for the teams
  • 6. Grani on Ice & WordPress ▪ I’ve been responsible for the sites for 05 and 07 teams, as I have children on those teams ▪ Implemented them with WordPress to keep things simple and maintainable ▪ WordPress did not have any good sports leaderboard plugins, so I decided to wrote my own
  • 7.
  • 8.
  • 9. Leaderboards ▪ Program - matches with teams, times, and location ▪ Game results with goals ▪ Ranking with divisions, semifinals, and finals ▪ Top scorers, top goals, and top assists ▪ Top saves for goaltenders ▪ Player lists for each team
  • 10. Data Model Team Player Goal Save Game Tied to a division, contains information about serie Intermissions Breaks between games
  • 11.
  • 12. Variations ▪ Tournaments have different scoring systems ▪ Depends on number of teams, whether game is played on full or half ice, etc. ▪ Also, all statistics are not gathered for younger players (goalie saves) ▪ It was also decided not to collect penalties or on-ice statistics (fair play, +/- saldo)
  • 14. Core Plugin Concepts ▪ Plugin provides admin interfaces for ▪ Managing player, team, etc. data for admins ▪ Adding and modifying game results for editors ▪ Leaderboards are created using shortcodes ▪ Can be inserted into normal pages and content can be added around them
  • 15. Technical Considerations ▪ Each admin interface page and shortcode has its own function ▪ Admin functions use simple helper function to generate data tables ▪ Helper functions for frequently used actions ▪ Number of different sort routines to order the results of the leaderboards ▪ Plugin generates HTML in shortcodes ▪ Styled inside theme CSS (or similar)
  • 16.
  • 17. Initialisation ▪ Configuration is red from a separate PHP file ▪ Tournament specific data isolated into that file ▪ Two actions registered for admin menu and enqueuing JavaScript ▪ Eight shortcodes added to support all leaderboards
  • 18. On Code Level register_activation_hook(__FILE__, 'gtInstall'); add_action('admin_menu', 'gtMenu'); add_action('wp_enqueue_scripts', 'gtScripts'); add_shortcode('gt_standings', 'gtShowStandings'); add_shortcode('gt_matches', 'gtShowMatches'); add_shortcode('gt_program', 'gtShowProgram'); add_shortcode('gt_goals', 'gtShowGoals'); add_shortcode('gt_saves', 'gtShowSaves'); add_shortcode('gt_current', 'gtShowCurrent'); add_shortcode('gt_players', 'gtShowPlayers'); add_shortcode('gt_shots', 'gtShowShots');
  • 19. Admin Interfaces ▪ Admin interfaces are either tables showing data or forms used to add or edit data ▪ Tables are generated inside admin page function ▪ Forms are created using a helper function
  • 20. On Code Level // Admin table generation for team listing echo '<table class="wp-list-table widefat"><thead><tr><th>Name</th><th>Division</th><th>Position</th><th>Sweepstake</ th><th>Actions</th></tr></thead><tbody>'; $i = 0; foreach($dt['teams'] as $t) { echo '<tr', (($i++) % 2 == 0 ? ' class="alternate"' : ''), '><td>', $t['name'], '</td><td>', $t['division'], '</td><td>', $t['position'], '</td><td>', $t['sweepstake'], '</td><td><a href="', $currentUrl, '&edit=', $t['id'], '">Edit</a> | <a href="', $currentUrl, '&remove=', $t['id'], '">Remove</a></td></tr>'; } echo '</tbody></table>';
  • 21. On Code Level // Form generation for adding and editing teams $teamData = array('id' => '', 'name' => '', 'division' => '', 'position' => '', 'sweepstake' => '', 'submit' => 'Add'); if($editTeam) { $teamData = array('id' => $editTeam['id'], 'name' => $editTeam['name'], 'division' => $editTeam['division'], 'position' => $editTeam['position'], 'sweepstake' => $editTeam['sweepstake'], 'submit' => 'Modify'); } $teamForm = array(array('name' => 'id', 'type' => 'hidden', 'value' => $teamData['id']), [...]
  • 22. On Code Level if(!$editTeam) { echo '<h3>Add Team</h3>'; } echo '<form action="" method="post"><input type="hidden" name="page" value="gtTournamentTeams">'; gtFormTable($teamForm); echo '</form>'; if($editTeam) { echo '<p><a href="', $_SERVER['PHP_SELF'], '?page=gtTournamentTeams">Back to Teams</a></p></div>'; }
  • 23. Admin Rights ▪ Two different user levels ▪ Admin users can manage everything ▪ Editors can input goals, saves, and manage game starts + ends ▪ Handled by showing extra menu items based on user rights
  • 24. On Code Level function gtMenu() { add_menu_page('Grani Tournament', 'Tournament', 'edit_posts', 'gtTournament', 'gtEnterScores'); add_submenu_page('gtTournament', 'Grani Tournament Teams', 'Manage Teams', 'install_plugins', 'gtTournamentTeams', 'gtModifyTeams'); add_submenu_page('gtTournament', 'Grani Tournament Players', 'Manage Players', 'install_plugins', 'gtTournamentPlayers', 'gtModifyPlayers'); add_submenu_page('gtTournament', 'Grani Tournament Games', 'Manage Games', 'install_plugins', 'gtTournamentGames', 'gtModifyGames'); add_submenu_page('gtTournament', 'Grani Tournament Intermissions', 'Manage Intermissions', 'install_plugins', 'gtTournamentIntermissions', 'gtModifyIntermissions'); add_menu_page('Slap Shots', 'Slap shots', 'edit_posts', 'gtTournamentShots', 'gtEnterShots'); }
  • 25. Leaderboard Calculation ▪ The leaderboards are not stored into the database, but calculated on the fly ▪ One function reads data from the database and calculates game scores, team points and positions ▪ The amount of data read and calculations made depend on the parameters - four steps in total
  • 26. On Code Level function gtReadData($players = false, $games = false, $intermissions = false, $saves = false) { global $wpdb; global $gtParams; $ret = array(); $teamRows = $wpdb->get_results("SELECT id, name, division, position, sweepstake FROM ${gtParams['teamTable']} ORDER BY division, position, name"); $ret['teams'] = array(); $teamDivPos = array();
  • 27. On Code Level foreach($teamRows as $r) { $t = array(); $t['id'] = $r->id; $t['name'] = $r->name; $t['position'] = $r->position; $t['division'] = $r->division; $t['sweepstake'] = $r->sweepstake; $ret['teams']['' . $r->id] = $t; $teamDivPos[$r->division . 'T' . $r->position] = $r->id; }
  • 28. On Code Level if($players) { $playerRows = $wpdb->get_results("SELECT id, team, number, name FROM $gtParams['playerTable']} ORDER BY team, number, name"); $ret['players'] = array(); foreach($playerRows as $r) { $p = array(); $p['id'] = $r->id; $p['team'] = $r->team; $p['name'] = $r->name; $p['number'] = $r->number; $ret['players']['' . $r->id] = $p; } }
  • 29. Leaderboard Display ▪ The shortcode functions request calculated data ▪ The data contains all information required for the leaderboard display ▪ The actual leaderboard generation is a simple foreach() loop ▪ With ugly HTML generation inside
  • 30.
  • 31. On Code Level // Snippet from showing goalie saves foreach($totalsByPlayer as $k => $v) { $ratio = number_format($v['ratio'] * 100, 1); if($ratio != $prevRatio) { $pos += $inc; $inc = 1; $prevRatio = $ratio; } else { $inc++; }
  • 32. On Code Level $ret .= '<tr class="gtToggler ' . ($i % 2 == 0 ? 'odd' : 'even') . '" id="gtSavesPlayer_' . $k . '"><td>' . $pos . '.</td><td colspan="2">' . $dt['players'][$k]['name'] . ' (' . $dt['players'][$k]['number'] . ')</td><td class="gtTogglerCue">' . $dt['teams'][$dt['players'][$k]['team']]['name'] . ($gtParams['useLevels'] ? ' &#8210; ' . str_repeat('A', ($dt['teams'][$dt['players'][$k]['team']]['division']{0})) : '') . '</td><td class="align-right">' . $v['saves'] . '</td><td class="align-right">' . $v['goals'] . '</td><td class="align-right">' . $ratio . '%</td></tr>';
  • 33. On Code Level foreach($dt['games'] as $gk => $gv) { if(isset($gamesByPlayer[$k][$gk])) { $g = $gamesByPlayer[$k][$gk]; $tot = $g['saves'] + $g['goals']; $ret .= '<tr class="gtToggled gtSavesPlayer_' . $k . '_games"><td>' . substr($gv['time'], 0, 5) . '</td><td>' . $dt['teams'][$gv['home']]['name'] . '</td><td>&nbsp;vs&nbsp;</td><td>' . $dt['teams'][$gv['away']]['name'] . '</td><td class="align-right">' . $g['saves'] . '</td><td class="align-right">' . $g['goals'] . '</td><td class="align-right">' . ($tot > 0 ? number_format($g['saves'] * 100 / ($g['saves'] + $g['goals']), 1) : '-') . '%</td></tr>'; } } $i++; }
  • 34. Digital Signage Support ▪ Certain leaderboards can be shown on big displays ▪ The system rotates leaderboards and ads using JavaScript ▪ The leaderboards scroll
  • 35. DS Implementation ▪ A couple of jQuery functions that ▪ Remove redundant items from the page ▪ Increase font sizes ▪ Scroll leaderboards ▪ Change pages with fade effect
  • 36. On Code Level if(window.location.search == '?leaderboard') { $('#header').hide(); $('#widgets').hide(); $('.post-edit').hide(); $('#footer').hide(); $('.tournamentLinks').hide(); $('#content').removeClass('col-620').addClass('col-940') .css('font-size', '250%').css('line-height', '1.5em') .css('margin-bottom', '0'); $('#container').css('max-width', '90%'); $('.gtTogglerCue').removeClass('gtTogglerCue'); [...]
  • 37. On Code Level if($('#fullscreenad').length > 0) { setTimeout(function() { loader(); }, 18000); } else { var speed = 0.05; var distance = $("#wrapper").height() - $(window).height() + $("#wrapper").offset().top + 50; var animationTime = distance / speed;
  • 38. On Code Level if(animationTime < 0) { animationTime = 0; } if($(window).height() < $(document).height() && animationTime > 0){ $('#container').css('overflow', 'hidden') .height($(window).height() - 0); setTimeout(function() { $('#wrapper').animate({ marginTop: -distance }, animationTime, 'linear'); }, 5000);
  • 39. Way Forward ▪ No new requirements on the horizon ▪ Handles all major needs for GrIFK tournaments ▪ Maybe new tournament models needed
  • 40. To Public Plugin? ▪ Would require a lot of extra work that adds no value to GrIFK tournaments ▪ More tournament models required -> calculation would be more generic and thus complex ▪ Admin interfaces should be made prettier ▪ Input validation needed