【Cocoon機能アップカスタマイズ集】:コードボックス(スクロール+コピー+行番号+色指定対応)

この記事では、Cocoonテーマで記事中のソースコードを「見やすく・使いやすく」表示するための、改良版コードボックスをご紹介します。
プラグイン不要で、行番号・背景色・コピー機能・余白対策がすべて実装可能です。


対応バージョン

  • Cocoon Ver. 2.8.8
  • Cocoon Child Ver. 1.1.3
  • WordPress 6.x 対応

カスタマイズ概要

このカスタマイズを導入すると、以下のようなコードブロックを表示できます👇

  • ✅ スクロール可能なコード領域
  • ✅ Copyボタンでワンクリックコピー
  • ✅ 行番号付きで可読性アップ
  • ✅ 背景色・文字色を自由に指定

functions.php に追加

Cocoon子テーマの functions.php に、以下のコードを追加してください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/* ============================================================================
 * class        : NS_Codebox
 * description  : Cocoon 子テーマ用「codebox」ショートコード
 * parameter    :
 *   language   : 任意の言語名
 *   bg         : 背景色(設定は3桁及び6桁指定)
 *   color      : 文字色
 *   nolines    : 行番号を非表示にする場合は「true」
 *   height     : コードボックスの表示高さ
 *   level      : codeboxの入れ子対応有無(1=yes/2=no)
 * notice       : HTMLブロック対応(整形防止)
 * ============================================================================
 *  rev.  |    date    |     author     |              description
 * -------+------------+----------------+--------------------------------------
 * @0v0.0 | 2025.11.11 |it-koubou.jax.jp| designed
 * ============================================================================
 */
class NS_Codebox {

    /** 初期化 **/
    public static function init() {
        add_shortcode('codebox', [__CLASS__, 'shortcode']);
        add_filter('the_content', [__CLASS__, 'protect_before_wpautop'], 1);
        add_filter('the_content', [__CLASS__, 'restore_after_wpautop'], 100);
        add_action('wp_footer', [__CLASS__, 'assets']);
    }

    /*---------------------------------------------
      ショートコード本体
    ---------------------------------------------*/
    public static function shortcode($atts, $content = null) {
        $atts = shortcode_atts([
            'language' => '',
            'bg'       => '#111',
            'color'    => '#fff',
            'nolines'  => 'false',
            'height'   => '420',
        ], $atts);

        $bg       = self::sanitize_color($atts['bg']);
        $color    = self::sanitize_color($atts['color']);
        $language = $atts['language'];
        $nolines  = ($atts['nolines'] === 'true');
        $height   = intval($atts['height']);

        $content = trim($content, "\n\r");
        $lines = explode("\n", $content);
        $lineNumbers = '';
        foreach ($lines as $i => $_) {
            $lineNumbers .= ($i + 1) . "\n";
        }

        ob_start(); ?>
        <div class="ns-code-box" style="background:<?php echo esc_attr($bg); ?>; color:<?php echo esc_attr($color); ?>;">
            <button class="ns-copy-button" onclick="nsCopyCode(this)">📋 コピー</button>
            <div class="ns-scroll-code" style="max-height:<?php echo esc_attr($height); ?>px;">
                <div class="ns-code-inner <?php echo $nolines ? 'no-lines' : ''; ?>">
                    <?php if (!$nolines): ?>
                        <pre class="ns-line-numbers"><code><?php echo esc_html($lineNumbers); ?></code></pre>
                    <?php endif; ?>
                    <pre class="ns-code-content"><code class="<?php echo esc_attr($language); ?>"><?php echo esc_html($content); ?></code></pre>
                </div>
            </div>
        </div>
        <?php
        return ob_get_clean();
    }

    /*---------------------------------------------
      カラーコード自動補正
    ---------------------------------------------*/
    private static function sanitize_color($color, $default = '#000') {
        $color = trim($color);
        if ($color && $color[0] !== '#') $color = '#' . $color;
        if (preg_match('/^#([0-9a-fA-F]{3})$/', $color, $m)) {
            $color = '#' . $m[1][0] . $m[1][0] . $m[1][1] . $m[1][1] . $m[1][2] . $m[1][2];
        }
        if (!preg_match('/^#([0-9a-fA-F]{6})$/', $color)) {
            $color = $default;
        }
        return $color;
    }

    /*---------------------------------------------
      入れ子ショートコード 保護処理
    ---------------------------------------------*/
    public static function protect_before_wpautop($content) {
        if (false === strpos($content, '[codebox')) return $content;

        $GLOBALS['ns_codebox_placeholders'] = [];
        $placeholders = [];
        $index = 0;
        $offset = 0;
        $pattern = '/\[codebox\b([^\]]*)\]/i';

        while (preg_match($pattern, $content, $m, PREG_OFFSET_CAPTURE, $offset)) {
            $fullMatch = $m[0][0];
            $startPos  = $m[0][1];
            $attrStr   = $m[1][0];
            $atts = shortcode_parse_atts($attrStr);
            $level = isset($atts['level']) ? intval($atts['level']) : 1;

            $pos = $startPos + strlen($fullMatch);
            $depth = 0;
            $endPos = false;

            while (preg_match('/\[\/codebox\]/i', $content, $close, PREG_OFFSET_CAPTURE, $pos)) {
                $foundPos = $close[0][1];
                if (preg_match('/\[codebox\b/i', substr($content, $pos, $foundPos - $pos))) {
                    $depth++;
                }
                $depth--;
                if ($depth < ($level - 1)) {
                    $endPos = $foundPos;
                    break;
                }
                $pos = $foundPos + strlen($close[0][0]);
            }
            if ($endPos === false) break;

            $innerContent = substr($content, $startPos + strlen($fullMatch), $endPos - ($startPos + strlen($fullMatch)));
            $fullBlock = substr($content, $startPos, $endPos - $startPos + strlen('[/codebox]'));

            $index++;
            $rendered = self::shortcode($atts, $innerContent);
            $key = "<!--NS_CODEBOX_PLACEHOLDER_{$index}-->";
            $placeholders[$key] = $rendered;

            $content = substr_replace($content, $key, $startPos, strlen($fullBlock));
            $offset = $startPos + strlen($key);
        }

        if (!empty($placeholders)) {
            $GLOBALS['ns_codebox_placeholders'] = $placeholders;
        }
        return $content;
    }

    public static function restore_after_wpautop($content) {
        if (!empty($GLOBALS['ns_codebox_placeholders'])) {
            $content = str_replace(array_keys($GLOBALS['ns_codebox_placeholders']), array_values($GLOBALS['ns_codebox_placeholders']), $content);
            $GLOBALS['ns_codebox_placeholders'] = [];
        }
        return $content;
    }

    /*---------------------------------------------
      CSS・JS 出力
    ---------------------------------------------*/
    public static function assets() { ?>
        <style>
            .ns-code-box {
                position: relative;
                border-radius: 8px;
                margin: 1.2em 0;
                overflow: hidden;
                font-family: "Courier New", Consolas, monospace;
                font-size: 14px;
                line-height: 1.6;
            }
            .ns-scroll-code { max-height: 420px; overflow: auto; padding: 0; }
            .ns-code-inner { display: grid; grid-template-columns: auto 1fr; align-items: start; }
            .ns-code-box.no-lines .ns-code-inner { display: block; }

            .ns-line-numbers {
                margin: 0;
                padding: 12px 8px 12px 10px;
                background: rgba(255,255,255,0.05);
                color: rgba(200,200,200,0.6);
                text-align: right;
                white-space: pre;
                user-select: none;
                border-right: 1px solid rgba(255,255,255,0.15);
            }
            .ns-line-numbers code { display: block; font-family: inherit; }

            .ns-code-content {
                margin: 0;
                padding: 12px 14px;
                white-space: pre;
                overflow-x: auto;
            }
            .ns-code-content code {
                display: block;
                font-family: inherit;
                color: inherit;
            }

            .ns-copy-button {
                position: absolute;
                top: 8px;
                right: 12px;
                z-index: 5;
                background: #4caf50;
                color: #fff;
                border: none;
                padding: 6px 10px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 13px;
            }
            .ns-copy-button:hover { background: #45a049; }
            .ns-copy-button.copied { background: #2196f3; }
            .ns-scroll-code pre { margin: 0; border: none; background: transparent; }

            @media screen and (max-width: 480px) {
                .ns-copy-button { top: 6px; right: 8px; padding: 5px 8px; }
            }
        </style>

        <script>
            function nsCopyCode(btn) {
                const codeElement = btn.parentElement.querySelector('.ns-code-content code');
                if (!codeElement) return;
                const text = codeElement.innerText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
                const trimmed = text.replace(/^\s*\n/, '').replace(/\n\s*$/, '');
                navigator.clipboard.writeText(trimmed).then(() => {
                    btn.textContent = '✅ コピー済み';
                    btn.classList.add('copied');
                    setTimeout(() => {
                        btn.textContent = '📋 コピー';
                        btn.classList.remove('copied');
                    }, 1800);
                }).catch(() => alert('コピーに失敗しました'));
            }
        </script>
    <?php }
}
// 初期化
NS_Codebox::init();

使用方法(投稿での書き方)

投稿エディターの「HTMLブロック(カスタムHTML)」に以下のように記述します👇

1
2
3
4
5
[codebox language="php" bg="#111" color="#fff"]
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
[/codebox]

背景色・文字色・行番号などは次のように調整できます。

属性説明初期値
language任意の言語名空(無指定)
bg背景色(例: #000, #f8f8f8)
設定は3桁及び6桁指定
#111(灰色)
color文字色(例: #fff, #111)#fff(白)
nolines行番号を非表示にする場合は「true」false
heightコードボックスの表示高さ420(px)
levelcodeboxの入れ子対応 = 1
codeboxの入れ子非対応 = 2
1

表示サンプル

黒背景・行番号付きサンプル

1
2
3
4
5
6
7
8
9
10
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!

白背景・行番号無しサンプル

Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!
Hello Cocoon!

特徴まとめ

  • ✅ Copyボタンで即コピー
  • ✅ 背景・文字色を自由に指定
  • ✅ 行番号のON/OFFが可能
  • ✅ 余白なしで美しく整列
  • ✅ Cocoonアップデートにも影響されにくい

まとめ

このカスタマイズは、Cocoonテーマでコードを紹介する記事に最適です。
PHP・HTML・CSSなどを安全に掲載でき、読者も簡単にコピーできます。
プラグイン不要・軽量・シンプルに実現できるのが最大の魅力です。


タイトルとURLをコピーしました