WordPressテーマ「Cocoon」には、投稿ごとにカスタムCSSやJavaScriptを設定できる便利な機能があります。
記事ごとに少しデザインを調整したいときや、特定のページだけ動きを追加したいときにとても重宝します。
しかも、その投稿を表示する時だけCSSやJavaScriptが読み込まれるため、ブログ全体が重くなりにくいのも大きなメリットです。
私もこの機能をよく使っているのですが、記事数が増えてくると「どの記事にカスタムCSSやJavaScriptを書いたのか分からない…」という問題が出てきました。
確認するには、いちいち投稿を開いて編集画面を見る必要があり、だんだんと面倒に感じるようになります。
そこで今回は、この手間を減らして作業効率を上げるために、投稿一覧画面をカスタマイズしてみました。
といっても難しいものではなく、「カスタムCSSやJavaScriptを設定している記事が一目で分かるようにする」だけのシンプルなものです。
ですがこれだけでも、管理のしやすさはかなり改善されます。
同じように感じている方は、ぜひ参考にしてみてください。
ポップアップでCSS/JavaScriptの内容が確認できるようにしました。
また、簡単な編集も可能に!
追加した機能
- 投稿一覧に「CSS / JS」列を追加
- CSSやJSが設定されている記事の列にCSS/JSの文字を表示
- CSS/JSの文字をクリックで編集画面へ移動
- 該当のCSS/JS欄まで自動スクロール
- フィルター&並び替え対応
カスタム後の一覧画面
投稿一覧に赤枠の部分の表示が追加されます。

- 絞り込み機能、ソート機能
- CSS/JavaScriptの設定がある場合、★CSS(赤)、★JS(青)が表示される

- 表示された★CSS、★JSをクリックすると別ウィンドウで編集画面が開きCSS/JavaScript欄まで自動スクロール&展開されます
導入について
子テーマの functions.php に以下のコードを追加してください。
黄色いハイライトの部分を変更するとカラムの位置を変更できます
例:タイトルの後にしたい場合は、’date’を’title’に変更
固定ページには必要ない場合には、青色ハイライト部分を削除
// ==============================
// CSS/JS列 追加
// ==============================
add_filter('manage_posts_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'date') {
$new_columns['custom_css_js'] = 'CSS/JS';
}
}
return $new_columns;
});
add_filter('manage_pages_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'date') {
$new_columns['custom_css_js'] = 'CSS/JS';
}
}
return $new_columns;
});
// ==============================
// 列の表示(★+色+クリックで編集+スクロール指定)
// ==============================
function add_custom_css_js_column($column_name, $post_id) {
if ($column_name === 'custom_css_js') {
$css = get_post_meta($post_id, '_custom_css', true);
$js = get_post_meta($post_id, '_custom_js', true);
$flags = [];
$edit_link = get_edit_post_link($post_id);
if (!empty(trim($css))) {
$flags[] = '<a href="' . esc_url($edit_link . '&scroll=css') . '" target="_blank" title="CSSを編集" style="color:#d63638;font-weight:bold;">★CSS</a>';
}
if (!empty(trim($js))) {
$flags[] = '<a href="' . esc_url($edit_link . '&scroll=js') . '" target="_blank" title="JSを編集" style="color:#2271b1;font-weight:bold;">★JS</a>';
}
echo !empty($flags) ? implode('<br>', $flags) : '-';
}
}
add_action('manage_posts_custom_column', 'add_custom_css_js_column', 10, 2);
add_action('manage_pages_custom_column', 'add_custom_css_js_column', 10, 2);
// ==============================
// フィルター追加
// ==============================
add_action('restrict_manage_posts', function() {
$selected = $_GET['css_filter'] ?? '';
?>
<select name="css_filter">
<option value="">CSS/JSすべて</option>
<option value="css" <?php selected($selected, 'css'); ?>>CSSあり</option>
<option value="js" <?php selected($selected, 'js'); ?>>JSあり</option>
<option value="both" <?php selected($selected, 'both'); ?>>CSS + JS</option>
</select>
<?php
});
// ==============================
// フィルター処理+並び替え
// ==============================
add_action('pre_get_posts', function($query) {
if (!is_admin() || !$query->is_main_query()) return;
if (!empty($_GET['css_filter'])) {
$meta_query = [];
if ($_GET['css_filter'] === 'css') {
$meta_query[] = [
'key' => '_custom_css',
'compare' => '!=',
'value' => ''
];
}
if ($_GET['css_filter'] === 'js') {
$meta_query[] = [
'key' => '_custom_js',
'compare' => '!=',
'value' => ''
];
}
if ($_GET['css_filter'] === 'both') {
$meta_query[] = [
'relation' => 'AND',
[
'key' => '_custom_css',
'compare' => '!=',
'value' => ''
],
[
'key' => '_custom_js',
'compare' => '!=',
'value' => ''
]
];
}
$query->set('meta_query', $meta_query);
}
// 並び替え
if ($query->get('orderby') === 'custom_css_js') {
$query->set('meta_key', '_custom_css');
$query->set('orderby', 'meta_value');
}
});
// ==============================
// 並び替え対応
// ==============================
add_filter('manage_edit-post_sortable_columns', function($columns) {
$columns['custom_css_js'] = 'custom_css_js';
return $columns;
});
add_filter('manage_edit-page_sortable_columns', function($columns) {
$columns['custom_css_js'] = 'custom_css_js';
return $columns;
});
// ==============================
// 編集画面:自動スクロール
// ==============================
add_action('admin_footer', function() {
$screen = get_current_screen();
if ($screen->base !== 'post') return;
?>
<script>
(function() {
const params = new URLSearchParams(window.location.search);
const target = params.get('scroll');
if (!target) return;
let id = '';
if (target === 'css') id = 'custom_css';
if (target === 'js') id = 'custom_js';
function openAllMetaBoxes() {
document.querySelectorAll('.postbox').forEach(box => {
if (box.classList.contains('closed')) {
box.classList.remove('closed');
}
});
}
function scrollToTarget() {
const el = document.getElementById(id);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.style.border = '2px solid red';
el.style.backgroundColor = '#fff8f8';
} else {
setTimeout(scrollToTarget, 500);
}
}
// 実行順
setTimeout(() => {
openAllMetaBoxes(); // 折りたたみ解除
scrollToTarget(); // スクロール
}, 700);
})();
</script>
<?php
});
※ カスタム投稿一覧にも表示されるようになっています。
追加機能
一覧画面でせっかくなのでカスタムCSS/JavaScriptの内容が確認できる方が便利なので表示できるようにしました。
CSS/JavaScriptの内容表示
マウスオーバーで表示、一部のみ表示されますが、”全文”で全ての内容を表示することが出来ます。
また、コピーボタンでコード全体のコピーができます。

// ==============================
// CSS/JS列 追加
// ==============================
add_filter('manage_posts_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'date') {
$new_columns['custom_css_js'] = 'CSS/JS';
}
}
return $new_columns;
});
add_filter('manage_pages_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'date') {
$new_columns['custom_css_js'] = 'CSS/JS';
}
}
return $new_columns;
});
// ==============================
// 列の表示(クリック+プレビュー対応)
// ==============================
function add_custom_css_js_column($column_name, $post_id) {
if ($column_name === 'custom_css_js') {
$css = get_post_meta($post_id, '_custom_css', true);
$js = get_post_meta($post_id, '_custom_js', true);
$flags = [];
$edit_link = get_edit_post_link($post_id);
if (!empty(trim($css))) {
$preview = mb_substr($css, 0, 120);
$flags[] = '<a href="' . esc_url($edit_link . '&scroll=css') . '" target="_blank"
class="code-preview css"
data-full="' . esc_attr($css) . '"
data-preview="' . esc_attr($preview) . '"
style="color:#d63638;font-weight:bold;">★CSS</a>';
}
if (!empty(trim($js))) {
$preview = mb_substr($js, 0, 120);
$flags[] = '<a href="' . esc_url($edit_link . '&scroll=js') . '" target="_blank"
class="code-preview js"
data-full="' . esc_attr($js) . '"
data-preview="' . esc_attr($preview) . '"
style="color:#2271b1;font-weight:bold;">★JS</a>';
}
echo !empty($flags) ? implode('<br>', $flags) : '-';
}
}
add_action('manage_posts_custom_column', 'add_custom_css_js_column', 10, 2);
add_action('manage_pages_custom_column', 'add_custom_css_js_column', 10, 2);
// ==============================
// フィルター
// ==============================
add_action('restrict_manage_posts', function() {
$selected = $_GET['css_filter'] ?? '';
?>
<select name="css_filter">
<option value="">CSS/JSすべて</option>
<option value="css" <?php selected($selected, 'css'); ?>>CSSあり</option>
<option value="js" <?php selected($selected, 'js'); ?>>JSあり</option>
<option value="both" <?php selected($selected, 'both'); ?>>CSS + JS</option>
</select>
<?php
});
// ==============================
// フィルター処理+並び替え
// ==============================
add_action('pre_get_posts', function($query) {
if (!is_admin() || !$query->is_main_query()) return;
if (!empty($_GET['css_filter'])) {
$meta_query = [];
if ($_GET['css_filter'] === 'css') {
$meta_query[] = [
'key' => '_custom_css',
'compare' => '!=',
'value' => ''
];
}
if ($_GET['css_filter'] === 'js') {
$meta_query[] = [
'key' => '_custom_js',
'compare' => '!=',
'value' => ''
];
}
if ($_GET['css_filter'] === 'both') {
$meta_query[] = [
'relation' => 'AND',
[
'key' => '_custom_css',
'compare' => '!=',
'value' => ''
],
[
'key' => '_custom_js',
'compare' => '!=',
'value' => ''
]
];
}
$query->set('meta_query', $meta_query);
}
if ($query->get('orderby') === 'custom_css_js') {
$query->set('meta_key', '_custom_css');
$query->set('orderby', 'meta_value');
}
});
// ==============================
// 並び替え
// ==============================
add_filter('manage_edit-post_sortable_columns', function($columns) {
$columns['custom_css_js'] = 'custom_css_js';
return $columns;
});
add_filter('manage_edit-page_sortable_columns', function($columns) {
$columns['custom_css_js'] = 'custom_css_js';
return $columns;
});
// ==============================
// 編集画面:自動スクロール+展開
// ==============================
add_action('admin_footer', function() {
$screen = get_current_screen();
if (!in_array($screen->base, ['post', 'edit'])) return;
?>
<script>
(function() {
const params = new URLSearchParams(window.location.search);
const target = params.get('scroll');
if (!target) return;
let id = '';
if (target === 'css') id = 'custom_css';
if (target === 'js') id = 'custom_js';
function openAllMetaBoxes() {
document.querySelectorAll('.postbox').forEach(box => {
if (box.classList.contains('closed')) {
box.classList.remove('closed');
}
});
}
function scrollToTarget() {
const el = document.getElementById(id);
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.style.border = '2px solid red';
el.style.backgroundColor = '#fff8f8';
} else {
setTimeout(scrollToTarget, 500);
}
}
setTimeout(() => {
openAllMetaBoxes();
scrollToTarget();
}, 700);
})();
</script>
<style>
.code-tooltip {
position: absolute;
background: #fff;
border: 1px solid #ccc;
padding: 10px;
max-width: 420px;
max-height: 300px;
overflow: auto;
font-size: 12px;
white-space: pre-wrap;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
z-index: 9999;
pointer-events: auto;
}
.code-actions {
margin-top: 8px;
display: flex;
justify-content: space-between;
}
.code-btn {
font-size: 11px;
padding: 4px 6px;
cursor: pointer;
background: #f0f0f0;
border: 1px solid #ccc;
}
.code-btn:hover {
background: #e0e0e0;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
let tooltip;
let hideTimeout;
document.querySelectorAll('.code-preview').forEach(el => {
el.addEventListener('mouseenter', function(e) {
clearTimeout(hideTimeout);
if (tooltip) tooltip.remove();
tooltip = document.createElement('div');
tooltip.className = 'code-tooltip';
const full = this.dataset.full;
const preview = this.dataset.preview;
tooltip.innerHTML = `
<div class="code-content">${preview}...</div>
<div class="code-actions">
<span class="code-btn show-full">全文</span>
<span class="code-btn copy-code">コピー</span>
</div>
`;
document.body.appendChild(tooltip);
tooltip.style.left = (e.pageX + 15) + 'px';
tooltip.style.top = (e.pageY + 15) + 'px';
tooltip.querySelector('.show-full').onclick = () => {
tooltip.querySelector('.code-content').textContent = full;
};
tooltip.querySelector('.copy-code').onclick = () => {
navigator.clipboard.writeText(full);
tooltip.querySelector('.copy-code').textContent = 'コピー済み';
};
tooltip.addEventListener('mouseenter', () => {
clearTimeout(hideTimeout);
});
tooltip.addEventListener('mouseleave', () => {
removeTooltip();
});
});
el.addEventListener('mouseleave', function() {
hideTimeout = setTimeout(removeTooltip, 300);
});
function removeTooltip() {
if (tooltip) {
tooltip.remove();
tooltip = null;
}
}
});
});
</script>
<?php
});
CSS/JavaScriptの内容表示、編集
マウスオーバーで表示された内容を編集可能にします。
実際、一覧画面で編集は必要か?と思ったのですが、色、幅等の変更とかちょっとしたことを変更したい場合には便利かも?と思いとりあえず機能を追加してみました。

// ==============================
// CSS/JS列 追加(タイトルの右)
// ==============================
add_filter('manage_posts_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'date') {
$new_columns['custom_css_js'] = 'CSS/JS';
}
}
return $new_columns;
});
add_filter('manage_pages_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'date') {
$new_columns['custom_css_js'] = 'CSS/JS';
}
}
return $new_columns;
});
// ==============================
// 列の表示(リンク+データ付与)
// ==============================
function add_custom_css_js_column($column_name, $post_id) {
if ($column_name === 'custom_css_js') {
$css = get_post_meta($post_id, '_custom_css', true);
$js = get_post_meta($post_id, '_custom_js', true);
$flags = [];
$edit_link = get_edit_post_link($post_id);
if (!empty(trim($css))) {
$preview = mb_substr($css, 0, 120);
$flags[] = '<a href="' . esc_url($edit_link . '&scroll=css') . '" target="_blank"
class="code-preview"
data-post="' . $post_id . '"
data-type="css"
data-full="' . esc_attr($css) . '"
data-preview="' . esc_attr($preview) . '"
style="color:#d63638;font-weight:bold;">★CSS</a>';
}
if (!empty(trim($js))) {
$preview = mb_substr($js, 0, 120);
$flags[] = '<a href="' . esc_url($edit_link . '&scroll=js') . '" target="_blank"
class="code-preview"
data-post="' . $post_id . '"
data-type="js"
data-full="' . esc_attr($js) . '"
data-preview="' . esc_attr($preview) . '"
style="color:#2271b1;font-weight:bold;">★JS</a>';
}
echo !empty($flags) ? implode('<br>', $flags) : '-';
}
}
add_action('manage_posts_custom_column', 'add_custom_css_js_column', 10, 2);
add_action('manage_pages_custom_column', 'add_custom_css_js_column', 10, 2);
// ==============================
// フィルター
// ==============================
add_action('restrict_manage_posts', function() {
$selected = $_GET['css_filter'] ?? '';
?>
<select name="css_filter">
<option value="">CSS/JSすべて</option>
<option value="css" <?php selected($selected, 'css'); ?>>CSSあり</option>
<option value="js" <?php selected($selected, 'js'); ?>>JSあり</option>
<option value="both" <?php selected($selected, 'both'); ?>>CSS + JS</option>
</select>
<?php
});
// ==============================
// フィルター処理+並び替え
// ==============================
add_action('pre_get_posts', function($query) {
if (!is_admin() || !$query->is_main_query()) return;
if (!empty($_GET['css_filter'])) {
$meta_query = [];
if ($_GET['css_filter'] === 'css') {
$meta_query[] = [
'key' => '_custom_css',
'compare' => '!=',
'value' => ''
];
}
if ($_GET['css_filter'] === 'js') {
$meta_query[] = [
'key' => '_custom_js',
'compare' => '!=',
'value' => ''
];
}
if ($_GET['css_filter'] === 'both') {
$meta_query[] = [
'relation' => 'AND',
[
'key' => '_custom_css',
'compare' => '!=',
'value' => ''
],
[
'key' => '_custom_js',
'compare' => '!=',
'value' => ''
]
];
}
$query->set('meta_query', $meta_query);
}
if ($query->get('orderby') === 'custom_css_js') {
$query->set('meta_key', '_custom_css');
$query->set('orderby', 'meta_value');
}
});
// ==============================
// 並び替え
// ==============================
add_filter('manage_edit-post_sortable_columns', function($columns) {
$columns['custom_css_js'] = 'custom_css_js';
return $columns;
});
add_filter('manage_edit-page_sortable_columns', function($columns) {
$columns['custom_css_js'] = 'custom_css_js';
return $columns;
});
// ==============================
// 編集画面:自動スクロール+展開
// ==============================
add_action('admin_footer', function() {
$screen = get_current_screen();
if (!in_array($screen->base,['post','edit'])) return;
?>
<script>
(function() {
const params = new URLSearchParams(window.location.search);
const target = params.get('scroll');
if (!target) return;
let id = target==='css'?'custom_css':'custom_js';
function openAllMetaBoxes(){ document.querySelectorAll('.postbox.closed').forEach(b=>b.classList.remove('closed')); }
function scrollToTarget(){
const el=document.getElementById(id);
if(el){ el.scrollIntoView({behavior:'smooth',block:'center'}); el.style.border='2px solid red'; el.style.backgroundColor='#fff8f8'; }
else setTimeout(scrollToTarget,500);
}
setTimeout(()=>{ openAllMetaBoxes(); scrollToTarget(); },700);
})();
</script>
<?php
});
// ==============================
// AJAX保存
// ==============================
add_action('wp_ajax_save_custom_code', function() {
if (!current_user_can('edit_posts')) wp_send_json_error();
$post_id = intval($_POST['post_id']);
$type = sanitize_text_field($_POST['type']);
$content = wp_unslash($_POST['content']);
if($type==='css') update_post_meta($post_id,'_custom_css',$content);
if($type==='js') update_post_meta($post_id,'_custom_js',$content);
wp_send_json_success();
});
// ==============================
// 管理画面 JS(ツールチップ+クリックで新規タブ+保存)
// ==============================
add_action('admin_footer', function() {
$screen = get_current_screen();
if (!in_array($screen->base,['edit','post'])) return;
?>
<style>
.code-tooltip{position:absolute;background:#fff;border:1px solid #ccc;padding:10px;max-width:420px;max-height:320px;overflow:auto;font-size:12px;white-space:pre-wrap;box-shadow:0 4px 12px rgba(0,0,0,0.2);z-index:9999;}
.code-actions{margin-top:8px;display:flex;justify-content:space-between;}
.code-btn{font-size:11px;padding:4px 6px;cursor:pointer;background:#f0f0f0;border:1px solid #ccc;}
.code-btn:hover{background:#e0e0e0;}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
let tooltip, hideTimeout, isEditing = false;
document.querySelectorAll('.code-preview').forEach(el => {
el.addEventListener('mouseenter', function(e) {
if (tooltip && isEditing) return;
clearTimeout(hideTimeout);
if (tooltip) tooltip.remove();
const full = this.dataset.full;
const preview = this.dataset.preview;
const postId = this.dataset.post;
const type = this.dataset.type;
tooltip = document.createElement('div');
tooltip.className = 'code-tooltip';
tooltip.dataset.full = full; // ← 全文を tooltip に保持
tooltip.innerHTML = `
<textarea class="code-content" style="width:100%;height:140px;">${preview}</textarea>
<div class="code-actions">
<span class="code-btn show-full">全文</span>
<span class="code-btn save-code">保存</span>
<span class="code-btn copy-code">コピー</span>
<span class="code-btn close-tip">閉じる</span>
</div>
`;
document.body.appendChild(tooltip);
tooltip.style.left = (e.pageX + 15) + 'px';
tooltip.style.top = (e.pageY + 15) + 'px';
const textarea = tooltip.querySelector('.code-content');
// 「全文」ボタン
tooltip.querySelector('.show-full').onclick = () => {
textarea.value = tooltip.dataset.full; // ← tooltip に保持した全文を取得
};
// コピー
tooltip.querySelector('.copy-code').onclick = () => {
navigator.clipboard.writeText(textarea.value);
tooltip.querySelector('.copy-code').textContent = 'コピー済み';
};
// 保存(AJAX + 即時反映)
tooltip.querySelector('.save-code').onclick = () => {
const newContent = textarea.value;
if (!confirm('この内容で保存しますか?')) return;
fetch(ajaxurl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
action: 'save_custom_code',
post_id: postId,
type: type,
content: newContent
})
})
.then(res => res.json())
.then(data => {
if (data.success) {
el.dataset.full = newContent;
el.dataset.preview = newContent.substring(0, 120);
tooltip.dataset.full = newContent; // ← tooltip 内の全文も更新
tooltip.querySelector('.save-code').textContent = '保存済み ✔';
textarea.style.border = '2px solid green';
}
});
};
// 閉じる
tooltip.querySelector('.close-tip').onclick = () => {
if (tooltip) { tooltip.remove(); tooltip = null; isEditing = false; }
};
// 編集中フラグ
textarea.addEventListener('focus', () => { isEditing = true; });
textarea.addEventListener('blur', () => { isEditing = false; });
// ツールチップ内マウス操作
tooltip.addEventListener('mouseenter', () => { clearTimeout(hideTimeout); });
tooltip.addEventListener('mouseleave', () => {
if (!isEditing) { tooltip.remove(); tooltip = null; isEditing = false; }
});
});
// マウス離脱で非表示
el.addEventListener('mouseleave', () => {
hideTimeout = setTimeout(() => {
if (!isEditing) { tooltip.remove(); tooltip = null; isEditing = false; }
}, 500);
});
// クリック時:新規タブで開く+保存
el.addEventListener('click', function(e) {
e.preventDefault();
const postId = this.dataset.post;
const type = this.dataset.type;
const content = this.dataset.full;
const href = this.href;
fetch(ajaxurl, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
action: 'save_custom_code',
post_id: postId,
type: type,
content: content
})
}).finally(() => {
window.open(href, '_blank');
});
});
});
});
</script>
<?php
});
さいごに
Cocoonの投稿ごとに設定できるカスタムCSSやJavaScriptはとても便利な機能ですが、記事数が増えてくると管理が大変になりがちです。
投稿一覧で一目で分かるようにするだけでも、作業効率はいくらか改善されると思います。
特に「どの記事にCSSを書いたか分からない…」と感じたことがある方には、あれば便利な機能だと思います。カスタマイズ自体もそれほど難しくないので、ぜひ一度試してみてください。


コメント