WordPress中实现带参数的PHP排行榜函数,通过短码控制返回的行数与列数
WordPress中实现带参数的PHP排行榜函数,通过短码控制返回的行数与列数
我来帮你一步步实现这个需求,WordPress短码的参数处理有固定套路,咱们可以通过修改现有函数,轻松实现按需返回指定行数和列的功能。直接上修改后的完整代码,之后再拆解关键改动:
function display_singles_ladder($atts) { global $wpdb; // 1. 处理短码参数,设置默认值 $args = shortcode_atts( array( 'limit' => null, // 默认返回所有行 'columns' => 'rank,player,matches_played,wins,losses,games_won,games_lost,win_streak,pending_challenges' // 默认显示所有列 ), $atts, 'singles_ladder' ); // 定义合法列映射:别名 => [表头文本, 数据键名] $allowed_columns = array( 'rank' => array('label' => 'Rank', 'data_key' => 'player_rank'), 'player' => array('label' => 'Player', 'data_key' => 'player_name'), 'matches_played' => array('label' => 'Matches Played', 'data_key' => 'matches_played'), 'wins' => array('label' => 'Match Wins', 'data_key' => 'wins'), 'losses' => array('label' => 'Match Losses', 'data_key' => 'losses'), 'games_won' => array('label' => 'Game Wins', 'data_key' => 'games_won'), 'games_lost' => array('label' => 'Game Losses', 'data_key' => 'games_lost'), 'win_streak' => array('label' => 'Win Streak', 'data_key' => 'win_streak'), 'pending_challenges' => array('label' => 'Challenges', 'data_key' => 'pending_challenges') ); // 过滤用户传入的列,只保留合法列 $selected_columns = array_intersect(explode(',', strtolower($args['columns'])), array_keys($allowed_columns)); // 防止用户传全错的列,至少保留核心列 if (empty($selected_columns)) { $selected_columns = array('rank', 'player'); } // 数据库表定义(和原函数一致) $ranking_table = $wpdb->prefix . 'player_rankings'; $players_table = $wpdb->prefix . 'players'; $match_players_table = $wpdb->prefix . 'match_players'; $matches_table = $wpdb->prefix . 'matches'; $results_table = $wpdb->prefix . 'match_results'; $game_scores_table = $wpdb->prefix . 'match_games'; // 2. 构建动态SQL查询,添加LIMIT条件 $sql = " SELECT r.player_id, r.player_rank, CONCAT(p.first_name, ' ', p.last_name) AS player_name, ( SELECT COUNT(*) FROM {$wpdb->prefix}challenges c WHERE c.challenged_id = p.player_id AND c.match_type_id = 1 AND c.status = 'pending' ) AS pending_challenges FROM $ranking_table r JOIN $players_table p ON r.player_id = p.player_id WHERE r.match_type_id = 1 ORDER BY r.player_rank ASC "; // 安全添加LIMIT(用prepare防止SQL注入) if (isset($args['limit']) && is_numeric($args['limit']) && $args['limit'] > 0) { $sql .= $wpdb->prepare(" LIMIT %d ", $args['limit']); } $players = $wpdb->get_results($sql, ARRAY_A); if (empty($players)) { return "<p>No ladder data available for singles.</p>"; } ob_start(); echo "<table class='singles-ladder'>"; echo "<thead><tr>"; // 3. 动态生成表头 foreach ($selected_columns as $col) { echo "<th>" . esc_html($allowed_columns[$col]['label']) . "</th>"; } echo "</tr></thead><tbody>"; foreach ($players as $player) { $player_id = (int)$player['player_id']; // 原有的比赛/游戏统计查询保持不变 $match_stats = $wpdb->get_row($wpdb->prepare(" SELECT COUNT(*) AS matches_played, SUM(CASE WHEN mp.team_number = 1 AND r.team1_score > r.team2_score THEN 1 WHEN mp.team_number = 2 AND r.team2_score > r.team1_score THEN 1 ELSE 0 END) AS wins, SUM(CASE WHEN mp.team_number = 1 AND r.team1_score < r.team2_score THEN 1 WHEN mp.team_number = 2 AND r.team2_score < r.team1_score THEN 1 ELSE 0 END) AS losses FROM $match_players_table mp JOIN $matches_table m ON mp.match_id = m.match_id JOIN $results_table r ON r.match_id = m.match_id WHERE mp.player_id = %d AND m.match_type_id = 1 ", $player_id), ARRAY_A); $game_stats = $wpdb->get_row($wpdb->prepare(" SELECT SUM(CASE WHEN mp.team_number = 1 AND gs.team1_score > gs.team2_score THEN 1 WHEN mp.team_number = 2 AND gs.team2_score > gs.team1_score THEN 1 ELSE 0 END) AS games_won, SUM(CASE WHEN mp.team_number = 1 AND gs.team1_score < gs.team2_score THEN 1 WHEN mp.team_number = 2 AND gs.team2_score < gs.team1_score THEN 1 ELSE 0 END) AS games_lost FROM $match_players_table mp JOIN $matches_table m ON mp.match_id = m.match_id JOIN $game_scores_table gs ON gs.match_id = m.match_id WHERE mp.player_id = %d AND m.match_type_id = 1 ", $player_id), ARRAY_A); $win_streak = get_player_win_streak($player_id); // 合并所有数据到一个数组,方便统一调用 $player_data = array_merge( $player, $match_stats, $game_stats, array('win_streak' => $win_streak) ); echo "<tr>"; // 4. 动态生成表格行内容 foreach ($selected_columns as $col) { $data_key = $allowed_columns[$col]['data_key']; $value = $player_data[$data_key] ?? ''; // 保留原有的特殊样式逻辑 if ($col === 'player') { $value .= $player['player_rank'] == 1 ? ' 👑' : ''; } if ($col === 'pending_challenges') { $value = $value > 0 ? "<span style='color: orange;'>⚔️ {$value} pending</span>" : "<span style='color: gray;'>—</span>"; } echo "<td>" . wp_kses_post($value) . "</td>"; } echo "</tr>"; } echo "</tbody></table>"; return ob_get_clean(); } add_shortcode('singles_ladder', 'display_singles_ladder');
关键改动说明
短码参数标准化处理
用shortcode_atts()统一管理参数,设置了合理的默认值,同时通过$allowed_columns过滤无效列,避免用户传错参数导致错误。安全的SQL LIMIT拼接
用$wpdb->prepare()处理LIMIT参数,彻底避免SQL注入风险,这是WordPress数据库操作的标准安全规范。动态表格渲染
表头和表格内容都通过循环$selected_columns生成,不用写一堆冗余的判断逻辑,后续新增列只需要在$allowed_columns里加映射即可。特殊逻辑的兼容
保留了原函数中冠军标记、挑战状态样式的特殊处理,确保这些细节在动态列中依然生效。
短码调用示例
现在你可以灵活控制显示内容了:
- 显示完整排行榜:
[singles_ladder] - 只显示前5名:
[singles_ladder limit="5"] - 只显示核心列:
[singles_ladder columns="rank,player,wins,losses"] - 组合使用:
[singles_ladder limit="3" columns="rank,player,win_streak"]
内容来源于stack exchange
相关产品推荐
相关产品推荐

