<?php
if ( ! isset( $content_width ) )
$content_width = 625;
/**
* SQOOLNETテーマのセットアップ
* TwentyTwelveの遺産を排除し、sqool_setup()に変更
*/
function sqool_setup() {
load_theme_textdomain( 'sqoolnet', get_template_directory() . '/languages' );
add_editor_style();
add_theme_support( 'automatic-feed-links' );
add_theme_support( 'post-formats', array( 'aside', 'image', 'link', 'quote', 'status' ) );
register_nav_menu( 'primary', __( 'Primary Menu', 'sqoolnet' ) );
add_theme_support( 'custom-background', array(
'default-color' => 'e6e6e6',
) );
add_theme_support( 'post-thumbnails', array( 'post', 'column', 'news', 'dreamnews', 'prwire','esports', 'business', 'businessnews', 'page','robot','blog','travel','review','report','notice','link','special','hints-and-tips','premium' ) );
add_image_size('thumb50', 50, 50, true);
add_image_size('thumb100', 100, 100, true);
add_image_size('thumb200', 200, 200, true);
add_image_size('thumb150_113', 150, 113, true);
add_image_size('thumb200_100', 200, 100, true);
add_image_size('thumb420_170', 420, 170, true);
add_image_size('thumb696', 696, 696, true);
set_post_thumbnail_size( 500,500,true ); // Unlimited height, soft crop
/* サムネイル取得関数からwidth&heightを除去 */
// → サムネイル関連の属性除去は remove_image_attribute() に集約
}
add_action( 'after_setup_theme', 'sqool_setup' );
/**
* shortcodeがpタグに囲まれるfix
*
*/
function shortcode_empty_paragraph_fix($content) {
$array = array (
'<p>[' => '[',
']</p>' => ']',
']<br />' => ']'
);
$content = strtr($content, $array);
return $content;
}
add_filter('the_content', 'shortcode_empty_paragraph_fix');
/**
* Add support for a custom header image.
*/
require( get_template_directory() . '/inc/custom-header.php' );
require( get_template_directory() . '/adsense.php' );
/**
* Return the Google font stylesheet URL if available.
*
* The use of Open Sans by default is localized. For languages that use
* characters not supported by the font, the font can be disabled.
*
* @since SQOOLNET 1.2
*
* @return string Font stylesheet or empty string if disabled.
*/
function sqool_get_font_url() {
$font_url = '';
/* translators: If there are characters in your language that are not supported
* by Open Sans, translate this to 'off'. Do not translate into your own language.
*/
if ( 'off' !== _x( 'on', 'Open Sans font: on or off', 'sqoolnet' ) ) {
$subsets = 'latin,latin-ext';
/* translators: To add an additional Open Sans character subset specific to your language,
* translate this to 'greek', 'cyrillic' or 'vietnamese'. Do not translate into your own language.
*/
$subset = _x( 'no-subset', 'Open Sans font: add new subset (greek, cyrillic, vietnamese)', 'sqoolnet' );
if ( 'cyrillic' == $subset )
$subsets .= ',cyrillic,cyrillic-ext';
elseif ( 'greek' == $subset )
$subsets .= ',greek,greek-ext';
elseif ( 'vietnamese' == $subset )
$subsets .= ',vietnamese';
$query_args = array(
'family' => 'Open+Sans:400italic,700italic,400,700',
'subset' => $subsets,
);
$font_url = add_query_arg( $query_args, 'https://fonts.googleapis.com/css' );
}
return $font_url;
}
/**
* Enqueue scripts and styles for front-end.
*
* @since SQOOLNET 1.0
*/
function sqool_scripts_styles() {
global $wp_styles;
/*
* Adds JavaScript to pages with the comment form to support
* sites with threaded comments (when in use).
*/
if ( is_singular() && comments_open() && get_option( 'thread_comments' ) )
wp_enqueue_script( 'comment-reply' );
// Adds JavaScript for handling the navigation menu hide-and-show behavior.
// jQuery依存を削除(Vanilla JSで実装済み)
// defer属性を追加してメインスレッドのブロックを防止
wp_enqueue_script( 'sqool-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20140711', true );
// HTML5 Shivは削除済み(IE8以下のサポート終了により不要)
$font_url = sqool_get_font_url();
if ( ! empty( $font_url ) )
wp_enqueue_style( 'sqool-fonts', esc_url_raw( $font_url ), array(), null );
// Loads our main stylesheet.
// wp_enqueue_style( 'sqool-style', get_stylesheet_uri() );
}
add_action( 'wp_enqueue_scripts', 'sqool_scripts_styles' );
/**
* Filter TinyMCE CSS path to include Google Fonts.
*
* Adds additional stylesheets to the TinyMCE editor if needed.
*
* @uses sqool_get_font_url() To get the Google Font stylesheet URL.
*
* @since SQOOLNET 1.0
*
* @param string $mce_css CSS path to load in TinyMCE.
* @return string Filtered CSS path.
*/
function sqool_mce_css( $mce_css ) {
$font_url = sqool_get_font_url();
if ( empty( $font_url ) )
return $mce_css;
if ( ! empty( $mce_css ) )
$mce_css .= ',';
$mce_css .= esc_url_raw( str_replace( ',', '%2C', $font_url ) );
return $mce_css;
}
add_filter( 'mce_css', 'sqool_mce_css' );
/**
* Filter the page title.
*
* Creates a nicely formatted and more specific title element text
* for output in head of document, based on current view.
*
* @since SQOOLNET 1.0
*
* @param string $title Default title text for current view.
* @param string $sep Optional separator.
* @return string Filtered title.
*/
function sqool_wp_title( $title, $sep ) {
global $paged, $page;
if ( is_feed() )
return $title;
// Add the site description for the home/front page.
$site_description = get_bloginfo( 'description', 'display' );
if ( $site_description && ( is_home() || is_front_page() ) )
$title = "$title $sep $site_description";
// Add a page number if necessary.
if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() )
$title = "$title $sep " . sprintf( __( 'Page %s', 'sqoolnet' ), max( $paged, $page ) );
return $title;
}
add_filter( 'wp_title', 'sqool_wp_title', 10, 2 );
/**
* Filter the page menu arguments.
*
* Makes our wp_nav_menu() fallback -- wp_page_menu() -- show a home link.
*
* @since SQOOLNET 1.0
*/
function sqool_page_menu_args( $args ) {
if ( ! isset( $args['show_home'] ) )
$args['show_home'] = true;
return $args;
}
add_filter( 'wp_page_menu_args', 'sqool_page_menu_args' );
/**
* Register sidebars.
*
* Registers our main widget area and the front page widget areas.
*
* @since SQOOLNET 1.0
*/
function sqool_widgets_init() {
register_sidebar( array(
'name' => __( 'Main Sidebar', 'sqoolnet' ),
'id' => 'sidebar-1',
'description' => __( 'Appears on posts and pages except the optional Front Page template, which has its own widgets', 'sqoolnet' ),
'before_widget' => '<aside id="%1$s" class="widget %2$s">',
'after_widget' => '</aside>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
register_sidebar( array(
'name' => __( 'First Front Page Widget Area', 'sqoolnet' ),
'id' => 'sidebar-2',
'description' => __( 'Appears when using the optional Front Page template with a page set as Static Front Page', 'sqoolnet' ),
'before_widget' => '<aside id="%1$s" class="widget %2$s">',
'after_widget' => '</aside>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
register_sidebar( array(
'name' => __( 'Second Front Page Widget Area', 'sqoolnet' ),
'id' => 'sidebar-3',
'description' => __( 'Appears when using the optional Front Page template with a page set as Static Front Page', 'sqoolnet' ),
'before_widget' => '<aside id="%1$s" class="widget %2$s">',
'after_widget' => '</aside>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
register_sidebar( array(
'name' => __( 'PC右サイドバー', 'sqoolnet' ),
'id' => 'sidebar-5',
'description' => __( 'PCの右端に表示されます', 'sqoolnet' ),
'before_widget' => '<aside id="%1$s" class="widget %2$s">',
'after_widget' => '</aside>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
}
add_action( 'widgets_init', 'sqool_widgets_init' );
if ( ! function_exists( 'sqool_content_nav' ) ) :
/**
* Displays navigation to next/previous pages when applicable.
*/
function sqool_content_nav( $html_id ) {
global $wp_query;
if ( $wp_query->max_num_pages > 1 ) : ?>
<nav id="<?php echo esc_attr( $html_id ); ?>" class="navigation" role="navigation">
<h3 class="assistive-text"><?php _e( 'Post navigation', 'sqoolnet' ); ?></h3>
<div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">←</span> Older posts', 'sqoolnet' ) ); ?></div>
<div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">→</span>', 'sqoolnet' ) ); ?></div>
</nav><!-- .navigation -->
<?php endif;
}
endif;
/* ------------------------------------------------------------------------- *
* コメント欄
/* ------------------------------------------------------------------------- */
if ( ! function_exists( 'sqool_comment' ) ) :
/**
* Template for comments and pingbacks.
*
* Used as a callback by wp_list_comments() for displaying the comments.
*/
function sqool_comment( $comment, $args, $depth ) {
$GLOBALS['comment'] = $comment;
switch ( $comment->comment_type ) :
case 'pingback' :
case 'trackback' :
// Display trackbacks differently than normal comments.
?>
<li <?php comment_class(); ?> id="comment-<?php comment_ID(); ?>">
<p><?php _e( 'Pingback:', 'sqoolnet' ); ?> <?php comment_author_link(); ?> <?php edit_comment_link( __( '(Edit)', 'sqoolnet' ), '<span class="edit-link">', '</span>' ); ?></p>
<?php
break;
default :
// Proceed with normal comments.
global $post;
?>
<li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>">
<article id="comment-<?php comment_ID(); ?>" class="comment">
<header class="comment-meta comment-author vcard">
<?php
echo get_avatar( $comment, 44 );
printf( '<cite class="fn">ID:%1$s %2$s</cite>', get_comment_ID(), get_comment_author_link(),
// If current post author is also comment author, make it known visually.
( $comment->user_id === $post->post_author ) ? '<span>' . __( 'Post author', 'sqoolnet' ) . '</span>' : ''
);
printf( '<a href="%1$s"><time datetime="%2$s">%3$s</time></a>',
esc_url( get_comment_link( $comment->comment_ID ) ),
get_comment_time( 'c' ),
/* translators: 1: date, 2: time */
sprintf( __( '%1$s at %2$s', 'sqoolnet' ), get_comment_date(), get_comment_time() )
);
?>
</header><!-- .comment-meta -->
<?php if ( '0' == $comment->comment_approved ) : ?>
<p class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'sqoolnet' ); ?></p>
<?php endif; ?>
<section class="comment-content comment">
<?php comment_text(); ?>
<?php edit_comment_link( __( 'Edit', 'sqoolnet' ), '<p class="edit-link">', '</p>' ); ?>
</section><!-- .comment-content -->
<div class="reply">
<?php comment_reply_link( array_merge( $args, array( 'reply_text' => __( 'Reply', 'sqoolnet' ), 'after' => ' <span>↓</span>', 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
</div><!-- .reply -->
</article><!-- #comment-## -->
<?php
break;
endswitch; // end comment_type check
}
endif;
function my_comment_form_fields( $fields){
//unset( $fields['author']); // 「名前」を非表示にする場合
unset( $fields['email']); // 「メールアドレス」を非表示にする場合
unset( $fields['url']); // 「ウェブサイト」を非表示にする場合
return $fields;
}
add_filter( 'comment_form_default_fields', 'my_comment_form_fields');
add_filter( 'comment_form_defaults', 'my_title_reply');
function my_title_reply( $defaults){
$defaults['title_reply'] = 'コメントを書き込む';
return $defaults;
}
add_filter( "comment_form_defaults", "my_comment_notes_before");
function my_comment_notes_before( $defaults){
$defaults['comment_notes_before'] = '';
return $defaults;
}
if ( ! function_exists( 'sqool_entry_meta' ) ) :
/**
* Set up post entry meta.
*
* Prints HTML with meta information for current post: categories, tags, permalink, author, and date.
*/
function sqool_entry_meta() {
global $post;
$author = get_the_author();
$categories_list = get_the_category_list( __( ', ', 'sqoolnet' ) );
$tag_list = get_the_tag_list( '', __( ', ', 'sqoolnet' ) );
$date = sprintf( '<a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s">%4$s</time></a>',
esc_url( get_permalink() ),
esc_attr( get_the_time() ),
esc_attr( get_the_date( 'c' ) ),
esc_html( get_the_date() )
);
// Translators: 1 is category, 2 is tag, 3 is the date and 4 is the author's name.
if ( $tag_list ) {
$utility_text = __( 'This entry was posted in %1$s and tagged %2$s on %3$s<span class="by-author"> by %4$s</span>.', 'sqoolnet' );
} elseif ( $categories_list ) {
$utility_text = __( 'This entry was posted in %1$s on %3$s<span class="by-author"> by %4$s</span>.', 'sqoolnet' );
} else {
$utility_text = __( 'This entry was posted on %3$s<span class="by-author"> by %4$s</span>.', 'sqoolnet' );
}
printf(
$utility_text,
$categories_list,
$tag_list,
$date,
$author
);
}
endif;
/**
* Extend the default WordPress body classes.
*
* Extends the default WordPress body class to denote:
* 1. Using a full-width layout, when no active widgets in the sidebar
* or full-width template.
* 2. Front Page template: thumbnail in use and number of sidebars for
* widget areas.
* 3. White or empty background color to change the layout and spacing.
* 4. Custom fonts enabled.
* 5. Single or multiple authors.
*
* @since SQOOLNET 1.0
*
* @param array $classes Existing class values.
* @return array Filtered class values.
*/
function sqool_body_class( $classes ) {
$background_color = get_background_color();
$background_image = get_background_image();
if ( ! is_active_sidebar( 'sidebar-1' ) || is_page_template( 'page-templates/full-width.php' ) )
$classes[] = 'full-width';
if ( is_page_template( 'page-templates/front-page.php' ) ) {
$classes[] = 'template-front-page';
if ( has_post_thumbnail() )
$classes[] = 'has-post-thumbnail';
if ( is_active_sidebar( 'sidebar-2' ) && is_active_sidebar( 'sidebar-3' ) )
$classes[] = 'two-sidebars';
}
if ( empty( $background_image ) ) {
if ( empty( $background_color ) )
$classes[] = 'custom-background-empty';
elseif ( in_array( $background_color, array( 'fff', 'ffffff' ) ) )
$classes[] = 'custom-background-white';
}
// Enable custom font class only if the font CSS is queued to load.
if ( wp_style_is( 'sqool-fonts', 'queue' ) )
$classes[] = 'custom-font-enabled';
if ( ! is_multi_author() )
$classes[] = 'single-author';
return $classes;
}
add_filter( 'body_class', 'sqool_body_class' );
/**
* Adjust content width in certain contexts.
*
* Adjusts content_width value for full-width and single image attachment
* templates, and when there are no active widgets in the sidebar.
*
* @since SQOOLNET 1.0
*/
function sqool_content_width() {
if ( is_page_template( 'page-templates/full-width.php' ) || is_attachment() || ! is_active_sidebar( 'sidebar-1' ) ) {
global $content_width;
$content_width = 960;
}
}
add_action( 'template_redirect', 'sqool_content_width' );
/**
* Register postMessage support.
*
* Add postMessage support for site title and description for the Customizer.
*
* @since SQOOLNET 1.0
*
* @param WP_Customize_Manager $wp_customize Customizer object.
*/
function sqool_customize_register( $wp_customize ) {
$wp_customize->get_setting( 'blogname' )->transport = 'postMessage';
$wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage';
$wp_customize->get_setting( 'header_textcolor' )->transport = 'postMessage';
}
add_action( 'customize_register', 'sqool_customize_register' );
/**
* Enqueue Javascript postMessage handlers for the Customizer.
*
* Binds JS handlers to make the Customizer preview reload changes asynchronously.
*
* @since SQOOLNET 1.0
*/
function sqool_customize_preview_js() {
wp_enqueue_script( 'sqool-customizer', get_template_directory_uri() . '/js/theme-customizer.js', array( 'customize-preview' ), '20141120', true );
}
add_action( 'customize_preview_init', 'sqool_customize_preview_js' );
/* 独自関数追加 */
/* 続きを読むのURL修正 */
function remove_more_jump_link( $link) {
$offset = strpos( $link, '#more-');
if ($offset) {
$end = strpos( $link, '"', $offset);
}
if ($end) {
$link = substr_replace( $link, '', $offset, $end-$offset);
}
return $link;
}
add_filter( 'the_content_more_link', 'remove_more_jump_link');
/* 投稿者非表示 */
// sqool_entry_meta() は上部の定義を利用
/* サイトバーでショートコードを使えるようにする */
// 安定化のため一時的に無効化(壊れたoption/metaを読みに行く可能性があるため)
// add_filter('widget_text', 'do_shortcode');
/* 寄稿者画像アップロード権限追加(DB書き込みを避けるため一度だけ実行) */
function sqool_maybe_allow_contributor_uploads_once() {
if ( get_option( 'sqool_allow_contributor_uploads_executed', false ) ) {
return;
}
$role = get_role( 'contributor' );
if ( $role && method_exists( $role, 'add_cap' ) ) {
$role->add_cap( 'upload_files' );
update_option( 'sqool_allow_contributor_uploads_executed', true, false );
}
}
add_action( 'admin_init', 'sqool_maybe_allow_contributor_uploads_once' );
/* メディアの抽出条件にログインユーザーの絞り込み条件を追加する */
function display_only_self_uploaded_medias( $wp_query ) {
if ( is_admin() && ( $wp_query->is_main_query() || ( defined( 'DOING_QUERY_ATTACHMENT' ) && DOING_QUERY_ATTACHMENT ) ) && $wp_query->get( 'post_type' ) == 'attachment' ) {
$user = wp_get_current_user();
$wp_query->set( 'author', $user->ID );
}
}
function define_doing_query_attachment_const() {
if ( ! defined( 'DOING_QUERY_ATTACHMENT' ) ) {
define( 'DOING_QUERY_ATTACHMENT', true );
}
}
// get_currentuserinfo();
// if($current_user->user_level < 10){
// add_action( 'pre_get_posts', 'display_only_self_uploaded_medias' );
// add_action( 'wp_ajax_query-attachments', 'define_doing_query_attachment_const', 0 );
// }
/* 他の人の投稿を見れないようにする */
/* 対象画面(edit.phpなど)・対象post_typeを明示して限定(管理画面の検索や特定画面で想定外の絞り込みを防ぐ) */
function exclude_other_posts( $wp_query ) {
// 管理画面の投稿一覧(edit.php)のみに限定($pagenowで確実に判定)
global $pagenow;
if ( $pagenow !== 'edit.php' ) {
return;
}
// リクエストパラメータからpost_typeを取得(明示的に指定されたもののみ)
$post_type = isset( $_REQUEST['post_type'] ) ? sanitize_text_field( $_REQUEST['post_type'] ) : 'post';
if ( ! post_type_exists( $post_type ) ) {
$post_type = 'post';
}
$post_type_obj = get_post_type_object( $post_type );
// プロパティの存在チェックを追加(エラー防止)
if ( $post_type_obj && isset( $post_type_obj->cap ) && isset( $post_type_obj->cap->edit_other_posts ) ) {
$cap_type = $post_type_obj->cap->edit_other_posts;
} else {
$cap_type = 'edit_others_posts';
}
// 対象post_typeに限定し、既にauthor指定がある場合はスキップ
// $wp_query->get('post_type') は配列になり得るため、is_array を吸収して判定
$qpt = $wp_query->get( 'post_type' );
$is_target_post_type = false;
if ( is_array( $qpt ) ) {
// 複数のpost_typeが指定されている場合
$is_target_post_type = in_array( $post_type, $qpt, true );
} elseif ( $qpt === $post_type ) {
// 単一のpost_typeが指定されている場合
$is_target_post_type = true;
} elseif ( empty( $qpt ) && $post_type === 'post' ) {
// post_typeが指定されていない場合はデフォルトで'post'として扱う
$is_target_post_type = true;
}
if ( is_admin()
&& $wp_query->is_main_query()
&& $is_target_post_type
&& ! $wp_query->get( 'author' )
&& ! current_user_can( $cap_type ) ) {
$user = wp_get_current_user();
$wp_query->set( 'author', $user->ID );
}
}
if(!current_user_can('manage_options')){
add_action( 'pre_get_posts', 'exclude_other_posts' );
}
/* メニュー表示制限 */
function my_remove_menu(){
remove_menu_page('wpcf7'); // Contact form 7の「お問い合わせ」を非表示
}
// 管理者以外は指定メニューを消す
if(!current_user_can('administrator'))
add_action('admin_menu', 'my_remove_menu');
/* 特定ユーザーに公開記事編集権限付与 */
/*
function edit_mypublished_posts() {
$user = new WP_User( '5' );
$user->add_cap( 'edit_published_posts','edit_pages' );
}
add_action( 'admin_init', 'edit_mypublished_posts');
*/
/* ユーザー の権限削除 */
/* 一度だけ実行する方式に変更(admin_initで毎回実行するとDB書き込みが増えるため) */
function remove_theme_caps(){
// 既に実行済みかチェック
$executed = get_option( 'sqool_remove_theme_caps_executed', false );
if ( $executed ) {
return;
}
$role = new WP_User( '55' );
$role->remove_cap( 'edit_published_posts' );
// 実行済みフラグを設定
update_option( 'sqool_remove_theme_caps_executed', true, false );
}
add_action( 'admin_init', 'remove_theme_caps' );
/* authorがありませんを解消 */
function remove_hentry( $classes ) {
$classes = array_diff($classes, array('hentry'));
return $classes;
}
add_filter('post_class', 'remove_hentry');
/* 固定ページに抜粋追加 */
add_post_type_support( 'page', 'excerpt' );
/* mymobile() タブレット除外関数 */
function isMobilePhone() {
// HTTP_USER_AGENTが存在しない環境(CLI・一部プロキシ・セキュリティ設定)でNoticeを避ける
if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
return false;
}
return (bool) preg_match('/android.+mobile|iemobile|ip(hone|od)|opera m(ob|in)i|psp|windows (ce|phone)|mobile.+firefox/i', $_SERVER['HTTP_USER_AGENT']);
}
/* 不要META削除 */
remove_action('wp_head', 'wp_generator');
remove_action('wp_head', 'rsd_link');
remove_action('wp_head', 'wlwmanifest_link');
// WP標準canonicalは無効化し、下の sqool_output_canonical() で明示的に出力する(SEO対策)
remove_action('wp_head', 'rel_canonical');
/**
* canonical を明示的に出力
* - .html でアクセスされている場合は、そのURL(末尾スラッシュ除去)を正とする
* - それ以外は WordPress の標準的なURL(get_permalink等)を用いる
*/
function sqool_output_canonical() {
if ( is_admin() || is_feed() ) {
return;
}
$canonical = '';
// .html でアクセスされている場合はリクエストURI優先
if ( isset( $_SERVER['REQUEST_URI'] ) && is_string( $_SERVER['REQUEST_URI'] ) ) {
$req = $_SERVER['REQUEST_URI'];
if ( preg_match( '#\.html(/)?$#i', $req ) ) {
$req = preg_replace( '#/+$#', '', $req );
$canonical = home_url( $req );
}
}
// 通常の canonical
if ( $canonical === '' ) {
if ( is_singular() ) {
// FeedWordPress記事の場合は引用元URLを優先
$post_id = get_queried_object_id();
if ( $post_id ) {
$source_url = get_post_meta($post_id, 'syndication_permalink', true);
$canonical = $source_url ? $source_url : get_permalink();
} else {
// $post_id が取れない場合のフォールバック(特殊クエリ等のケース)
$canonical = get_permalink();
}
} elseif ( is_front_page() ) {
$canonical = home_url( '/' );
} elseif ( is_home() ) {
// page_for_posts が設定されている場合のみ使用、無ければ home_url('/') にフォールバック
$page_for_posts = get_option( 'page_for_posts' );
if ( $page_for_posts && $page_for_posts > 0 ) {
$canonical = get_permalink( $page_for_posts );
} else {
$canonical = home_url( '/' );
}
} elseif ( is_category() || is_tag() || is_tax() ) {
$term = get_queried_object();
if ( $term && isset( $term->term_id ) ) {
$canonical = get_term_link( $term );
}
} elseif ( is_post_type_archive() ) {
$post_type = get_query_var( 'post_type' );
if ( $post_type ) {
$canonical = get_post_type_archive_link( $post_type );
}
} elseif ( is_search() ) {
$canonical = home_url( '/?s=' . rawurlencode( get_search_query() ) );
}
}
if ( is_wp_error( $canonical ) || ! is_string( $canonical ) || $canonical === '' ) {
return;
}
echo '<link rel="canonical" href="' . esc_url( $canonical ) . '" />' . "\n";
}
add_action( 'wp_head', 'sqool_output_canonical', 1 );
/* 抜粋カスタム */
function kotoriexcerpt($length) {
global $post;
if ( ! $post ) {
return '';
}
$content = mb_substr( strip_tags( $post->post_excerpt ), 0, $length );
if ( ! $content ) {
$content = $post->post_content;
$content = strip_shortcodes( $content );
$content = strip_tags( $content );
$content = str_replace( " ", "", $content );
$content = html_entity_decode( $content, ENT_QUOTES, "UTF-8" );
$content = mb_substr( $content, 0, $length );
}
return $content;
}
/* TOP固定ページ時のページネーション修正 */
add_action( 'parse_query', 'my_parse_query' );
function my_parse_query( $query ) {
if ( ! isset( $query->query_vars['paged'] ) && isset( $query->query_vars['page'] ) )
$query->query_vars['paged'] = $query->query_vars['page'];
}
/* 画像挿入時の不要ステータス除去 */
add_filter( 'image_send_to_editor', 'remove_image_attribute', 10 );
add_filter( 'post_thumbnail_html', 'remove_image_attribute', 10 );
/**
* 画像挿入時の不要属性除去
* 対象を画像リンクに限定(<a>タグの中に<img>がある場合のみ除去)
*/
function remove_image_attribute( $html ){
// width/height属性の除去(末尾のスペースも考慮)
$html = preg_replace( '/(width|height)\s*=\s*["\']\d*["\']\s*/i', '', $html );
// title属性の除去(シングル/ダブルクォート両対応)
$html = preg_replace( '/title\s*=\s*["\']([^"\']+)["\']/i', '', $html );
// <a>タグの除去は「画像リンクの場合のみ」に限定
// <a ...><img ...></a> の1組だけをマッチして、<img ...> だけを残す(誤爆防止)
// これにより、画像以外のリンク(本文やウィジェット内のテキストリンク等)は保護される
$html = preg_replace( '/<a\s+[^>]*>(.*?<img[^>]*>.*?)<\/a>/is', '$1', $html );
return $html;
}
/**
* post_thumbnailにitemprop="image"を追加する(1箇所に統合)
* 既にitemprop="image"が存在する場合は追加しない(重複防止)
*/
function custom_post_thumbnail($html){
// 既にitemprop="image"が存在する場合は何もしない
if ( strpos( $html, 'itemprop="image"' ) !== false || strpos( $html, "itemprop='image'" ) !== false ) {
return $html;
}
// <img タグに itemprop="image" を追加(属性の前に挿入)
return preg_replace( '/<img\s+/i', '<img itemprop="image" ', $html, 1 );
}
add_filter('post_thumbnail_html','custom_post_thumbnail',10,5);
// LCP画像の最適化: 最初のサムネイル画像からlazyloadクラスを削除し、fetchpriority="high"を追加
// メインクエリ・特定テンプレに限定(一覧や複数ループでの誤適用を防ぐ)
function sqool_optimize_lcp_image($html, $post_id, $post_thumbnail_id, $size, $attr) {
// 管理画面では処理しない
if ( is_admin() ) {
return $html;
}
// メインクエリでない場合はスキップ(一覧や複数ループでの適用を防ぐ)
global $wp_query;
if ( ! $wp_query->is_main_query() ) {
return $html;
}
// シングル投稿・固定ページのみに限定(アーカイブページでの適用を防ぐ)
if ( ! is_single() && ! is_page() ) {
return $html;
}
// グローバルカウンターで最初の画像を判定
static $image_count = 0;
$image_count++;
// 最初の画像(LCP候補)の場合のみ最適化
if ( $image_count === 1 ) {
// lazyloadクラスを削除
$html = str_replace(' lazyload', '', $html);
$html = str_replace('lazyload ', '', $html);
$html = str_replace(' lazyloaded', '', $html);
$html = str_replace('lazyloaded ', '', $html);
// loading="lazy"を削除
$html = preg_replace('/\s*loading=["\']lazy["\']/i', '', $html);
// fetchpriority="high"を追加(まだ存在しない場合)
if ( strpos($html, 'fetchpriority') === false ) {
$html = str_replace('<img', '<img fetchpriority="high"', $html);
}
// decoding="async"を追加(まだ存在しない場合)
if ( strpos($html, 'decoding=') === false ) {
$html = str_replace('<img', '<img decoding="async"', $html);
}
}
return $html;
}
// 優先度30で実行(remove_image_attributeの後)
add_filter('post_thumbnail_html', 'sqool_optimize_lcp_image', 30, 5);
/* カラム左サイドバー */
register_sidebar( array(
'name' => '左サイドバー',
'id' => 'sidebar-4',
'description' => '左サイドバー',
'before_widget' => '<aside id="%1$s" class="widget %2$s">',
'after_widget' => '</aside>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
/* 固定ページにカテゴリ追加 */
add_action('init','add_categories_for_pages');
function add_categories_for_pages(){
register_taxonomy_for_object_type('category', 'page');
}
add_action( 'pre_get_posts', 'nobita_merge_page_categories_at_category_archive' );
function nobita_merge_page_categories_at_category_archive( $query ) {
}
/* ニュース投稿ページパスワードカスタム */
function custom_password_form() {
global $post;
$label = 'pwbox-'.( empty( $post->ID ) ? rand() : $post->ID );
$o = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass', 'login_post' ) ) . '" method="post">
[news_post_lock]
<label for="' . $label . '">' . ' </label><input name="post_password" id="' . $label . '" type="password" maxlength="20" /> <input type="submit" name="Submit" value="' . esc_attr__( "パスワード送信" ) . '" />
</form>';
return $o;
}
add_filter( 'the_password_form', 'custom_password_form' );
/* 「保護中」を削除 */
add_filter('protected_title_format', 'remove_protected');
function remove_protected($title) {
return '%s';
}
/* パスワード保護クッキー保存時間 */
function custom_postpass_time() {
// post_passwordが存在しない場合は処理しない
if (!isset($_POST['post_password'])) return;
require_once ABSPATH . 'wp-includes/class-phpass.php';
$hasher = new PasswordHash( 8, true );
setcookie( 'wp-postpass_' . COOKIEHASH, $hasher->HashPassword( wp_unslash( $_POST['post_password'] ) ), time() + HOUR_IN_SECONDS, COOKIEPATH );
wp_safe_redirect( wp_get_referer() );
exit();
}
add_action( 'login_form_postpass', 'custom_postpass_time' );
//カテゴリー&タグ説明文のpタグを削除
remove_filter('term_description','wpautop');
/* emoji系のjs&css排除 */
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('admin_print_scripts', 'print_emoji_detection_script');
remove_action('wp_print_styles', 'print_emoji_styles' );
remove_action('admin_print_styles', 'print_emoji_styles');
/* jQueryの最適化:重複読み込みを防止し、最新版を使用 */
// 安定化のため一時的に無効化(依存関係の崩壊・document.writeによるブロッキング・不定期なフロント崩れを防ぐため)
/*
if (!is_admin()) {
function sqool_optimize_jquery(){
// 既存のjQueryを登録解除
wp_deregister_script('jquery');
wp_deregister_script('jquery-core');
wp_deregister_script('jquery-migrate');
// 最新のjQueryをフッターに読み込み(CDN使用、フォールバック付き)
// 注意: jQueryは他のスクリプトの依存関係があるため、deferは追加しない
wp_register_script('jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js', array(), '3.7.1', true);
wp_register_script('jquery-migrate', 'https://code.jquery.com/jquery-migrate-3.4.1.min.js', array('jquery'), '3.4.1', true);
// フォールバック(CDN失敗時)
add_filter('script_loader_tag', function($tag, $handle) {
if ($handle === 'jquery') {
$fallback = "if (typeof jQuery === 'undefined') { document.write('<script src=\"/wp-includes/js/jquery/jquery.min.js\"><\/script>'); }";
$tag = str_replace('</script>', '</script><script>' . $fallback . '</script>', $tag);
}
return $tag;
}, 10, 2);
wp_enqueue_script('jquery');
// jQuery Migrateは必要に応じてのみ読み込む(多くの場合不要)
// wp_enqueue_script('jquery-migrate');
}
add_action('wp_enqueue_scripts', 'sqool_optimize_jquery', 1);
}
*/
//wp_titleの$sepが「|」または半角スペースの場合は余分な空白削除
function my_title_fix($title, $sep, $seplocation){
if(!$sep || $sep == "|"){
$title = str_replace(' '.$sep.' ', $sep, $title);
}
return $title;
}
add_filter('wp_title', 'my_title_fix', 10, 3);
//post_is_in_descendant_categoryの有効化
if ( ! function_exists( 'post_is_in_descendant_category' ) ) {
function post_is_in_descendant_category( $cats, $_post = null ) {
foreach ( (array) $cats as $cat ) {
// get_term_children() は整数の ID しか受け付けない
$descendants = get_term_children( (int) $cat, 'category' );
if ( $descendants && in_category( $descendants, $_post ) )
return true;
}
return false;
}
}
//予約投稿対策 更新日が公開日より古くなるのを防ぐ
function get_mtime($format) {
$mtime = get_the_modified_time('Ymd');
$ptime = get_the_time('Ymd');
if ($ptime > $mtime) {
return get_the_time($format);
} elseif ($ptime === $mtime) {
return null;
} else {
return get_the_modified_time($format);
}
}
//更新日コントロール//
/* 管理画面が開いたときに実行 */
add_action( 'admin_menu', 'add_update_level_custom_box' );
/* 更新ボタンが押されたときに実行 */
add_action( 'save_post', 'save_custom_field_postdata' );
/* カスタムフィールドを投稿画面に追加 */
function add_update_level_custom_box() {
$post_types = sqool_get_post_types();
foreach ( $post_types as $post_type ) {
add_meta_box( 'update_level', '更新レベル', 'html_update_level_custom_box', $post_type, 'side', 'high' );
}
}
// 共通の投稿タイプ配列(再利用)
function sqool_get_post_types() {
return array( 'post', 'page', 'column', 'news', 'dreamnews', 'prwire', 'esports',
'business', 'businessnews', 'robot', 'blog', 'travel', 'review',
'report', 'notice', 'link', 'special', 'hints-and-tips', 'premium' );
}
/* 投稿画面に表示するフォームのHTMLソース */
function html_update_level_custom_box() {
global $post;
$update_level = get_post_meta( $post->ID, 'update_level', true );
echo '<div style="padding-top: 5px; overflow: hidden;">';
echo '<div style="padding:5px 0"><input name="update_level" type="radio" value="high" ';
if( $update_level == "" || $update_level == "high" ) echo ' checked="checked"';
echo ' />通常更新</div><div style="padding:5px 0"><input name="update_level" type="radio" value="low" ';
if( $update_level == "low" ) echo ' checked="checked"';
echo ' />修正のみ</div>';
echo '<div style="padding:5px 0"><input name="update_level" type="radio" value="del" ';
echo ' />更新日時消去(公開日時と同じにする)</div>';
echo '<div style="padding:5px 0;margin-bottom:10px"><input id="update_level_edit" name="update_level" type="radio" value="edit" ';
echo ' />更新日時変更</div>';
$datef = __( 'M j, Y @ G:i' );
if( get_the_date('c') ) {
$stamp = __('更新日時: <b>%1$s</b>');
}
else {
$stamp = __('更新日時: <b>未更新</b>');
}
$date = date_i18n( $datef, strtotime( $post->post_modified ) );
?>
<style>
.modtime { padding: 2px 0 1px 0; display: inline !important; height: auto !important; }
.modtime:before { font: normal 20px/1 'dashicons'; content: '\f145'; color: #888; padding: 0 5px 0 0; top: -1px; left: -1px; position: relative; vertical-align: top; }
#timestamp_mod_div { padding-top: 5px; line-height: 23px; }
#timestamp_mod_div p { margin: 8px 0 6px; }
#timestamp_mod_div input { border-width: 1px; border-style: solid; }
#timestamp_mod_div select { height: 21px; line-height: 14px; padding: 0; vertical-align: top;font-size: 12px; }
#aa_mod, #jj_mod, #hh_mod, #mn_mod { padding: 1px; font-size: 12px; }
#jj_mod, #hh_mod, #mn_mod { width: 2em; }
#aa_mod { width: 3.4em; }
</style>
<span class="modtime"><?php printf($stamp, $date); ?></span>
<div id="timestamp_mod_div" onkeydown="document.getElementById('update_level_edit').checked=true" onclick="document.getElementById('update_level_edit').checked=true">
<?php
$action = isset($_GET['action']) ? $_GET['action'] : 'edit';
touch_time_mod(($action == 'edit'), 1);
?>
</div>
</div>
<?php
}
/* 更新日時変更の入力フォーム */
function touch_time_mod( $edit = true, $unused = 0 ) {
global $wp_locale, $post;
// 引数はPHP8の警告回避のため受け取るが、実際の処理では関数内で$_GETから判定(既存ロジック維持)
$action = isset($_GET['action']) ? $_GET['action'] : 'edit';
$tab_index = 0;
$tab_index_attribute = "";
if ( (int) $tab_index > 0 ) {
$tab_index_attribute = " tabindex=\"$tab_index\"";
}
$jj_mod = mysql2date( 'd', $post->post_modified, false );
$mm_mod = mysql2date( 'm', $post->post_modified, false );
$aa_mod = mysql2date( 'Y', $post->post_modified, false );
$hh_mod = mysql2date( 'H', $post->post_modified, false );
$mn_mod = mysql2date( 'i', $post->post_modified, false );
$ss_mod = mysql2date( 's', $post->post_modified, false );
$month = '<label for="mm_mod" class="screen-reader-text">' . __( 'Month' ) .
'</label><select id="mm_mod" name="mm_mod"' . $tab_index_attribute . ">\n";
for ( $i = 1; $i < 13; $i = $i +1 ) {
$monthnum = zeroise($i, 2);
$month .= "\t\t\t" . '<option value="' . $monthnum . '" ' . selected( $monthnum, $mm_mod, false ) . '>';
$month .= sprintf( __( '%1$s-%2$s' ), $monthnum, $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ) );
$month .= "</option>\n";
}
$month .= '</select>';
$day = '<label for="jj_mod" class="screen-reader-text">' . __( 'Day' ) .
'</label><input type="text" id="jj_mod" name="jj_mod" value="' .
$jj_mod . '" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
$year = '<label for="aa_mod" class="screen-reader-text">' . __( 'Year' ) .
'</label><input type="text" id="aa_mod" name="aa_mod" value="' .
$aa_mod . '" size="4" maxlength="4"' . $tab_index_attribute . ' autocomplete="off" />';
$hour = '<label for="hh_mod" class="screen-reader-text">' . __( 'Hour' ) .
'</label><input type="text" id="hh_mod" name="hh_mod" value="' . $hh_mod .
'" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
$minute = '<label for="mn_mod" class="screen-reader-text">' . __( 'Minute' ) .
'</label><input type="text" id="mn_mod" name="mn_mod" value="' . $mn_mod .
'" size="2" maxlength="2"' . $tab_index_attribute . ' autocomplete="off" />';
printf( __( '%1$s %2$s, %3$s @ %4$s : %5$s' ), $month, $day, $year, $hour, $minute );
echo '<input type="hidden" id="ss_mod" name="ss_mod" value="' . $ss_mod . '" />';
}
/* 設定したカスタムフィールドの値をDBに書き込む記述 */
function save_custom_field_postdata( $post_id ) {
// 投稿編集画面以外では処理しない
if (!isset($_POST['update_level'])) return;
$mydata = $_POST['update_level'];
if( $mydata == "edit" ){ $mydata = "low"; }
elseif( $mydata == "del" ){ $mydata = ""; }
if( "" == get_post_meta( $post_id, 'update_level' )) {
/* update_levelというキーでデータが保存されていなかった場合、新しく保存 */
add_post_meta( $post_id, 'update_level', $mydata, true ) ;
} elseif( $mydata != get_post_meta( $post_id, 'update_level' )) {
/* update_levelというキーのデータと、現在のデータが不一致の場合、更新 */
update_post_meta( $post_id, 'update_level', $mydata ) ;
} elseif( "" == $mydata ) {
/* 現在のデータが無い場合、update_levelというキーの値を削除 */
delete_post_meta( $post_id, 'update_level' ) ;
}
}
/* 「修正のみ」は更新しない。それ以外は、それぞれの更新日時に変更する */
add_filter( 'wp_insert_post_data', 'my_insert_post_data', 10, 2 );
function my_insert_post_data( $data, $postarr ){
// 投稿編集画面以外では処理しない
if (!isset($_POST['update_level'])) return $data;
$mydata = $_POST['update_level'];
//プレスと 記事連携のあとに来たかフラグ
$pr_mail_flg = isset($_POST['pr_mail_flg']) ? (int)$_POST['pr_mail_flg'] : 0;
$link_mail_flg = isset($_POST['link_mail_flg']) ? (int)$_POST['link_mail_flg'] : 0;
//IPで 僕だけ見れるように
if ($_SERVER["REMOTE_ADDR"] == "222.158.251.43") {
// print_r($_POST);
// echo("aaaaaaaaaaaaaaaaaaaaaaaaa:::" . $mydata . "***" . $pr_mail_flg . "***" . $link_mail_flg);
}
if( $mydata == "low" || $pr_mail_flg == 1 || $link_mail_flg == 1 ){
unset( $data["post_modified"] );
unset( $data["post_modified_gmt"] );
}
elseif( $mydata == "edit" ) {
$aa_mod = isset($_POST['aa_mod']) && $_POST['aa_mod'] > 0 ? (int)$_POST['aa_mod'] : date('Y');
$mm_mod = isset($_POST['mm_mod']) && $_POST['mm_mod'] > 0 ? (int)$_POST['mm_mod'] : date('n');
$jj_mod = isset($_POST['jj_mod']) ? min(31, max(1, (int)$_POST['jj_mod'])) : date('j');
$hh_mod = isset($_POST['hh_mod']) ? ((int)$_POST['hh_mod'] > 23 ? (int)$_POST['hh_mod'] - 24 : (int)$_POST['hh_mod']) : 0;
$mn_mod = isset($_POST['mn_mod']) ? ((int)$_POST['mn_mod'] > 59 ? (int)$_POST['mn_mod'] - 60 : (int)$_POST['mn_mod']) : 0;
$ss_mod = isset($_POST['ss_mod']) ? ((int)$_POST['ss_mod'] > 59 ? (int)$_POST['ss_mod'] - 60 : (int)$_POST['ss_mod']) : 0;
$modified_date = sprintf( "%04d-%02d-%02d %02d:%02d:%02d", $aa_mod, $mm_mod, $jj_mod, $hh_mod, $mn_mod, $ss_mod );
if ( ! wp_checkdate( $mm_mod, $jj_mod, $aa_mod, $modified_date ) ) {
unset( $data["post_modified"] );
unset( $data["post_modified_gmt"] );
return $data;
}
$data["post_modified"] = $modified_date;
$data["post_modified_gmt"] = get_gmt_from_date( $modified_date );
}
elseif( $mydata == "del" ) {
$data["post_modified"] = $data["post_date"];
$data["post_modified_gmt"] = $data["post_date_gmt"];
}
return $data;
}
//更新日コントロールここまで//
/* feedにアイキャッチを追加 */
/*
function rss_post_thumbnail($content) {
global $post;
if(has_post_thumbnail($post->ID)) {
$content = '<p>' . get_the_post_thumbnail($post->ID) . '</p>' . $content;
}
return $content;
}
add_filter('the_excerpt_rss', 'rss_post_thumbnail');
add_filter('the_content_feed', 'rss_post_thumbnail');
*/
/* rssキャッシュ停止 */
function do_not_cache_feeds( $feed ) {
if ( is_object( $feed ) && method_exists( $feed, 'enable_cache' ) ) {
$feed->enable_cache( false );
}
}
add_action( 'wp_feed_options', 'do_not_cache_feeds' );
/* frrd・rssタイトル調整 */
function cat_added_title( $title) {
if(in_category(4591)|| post_is_in_descendant_category( '4591' )) {
if(in_category(24)|| post_is_in_descendant_category( '24' )) {
$cat_name = '脱出ゲーム攻略';
}elseif(in_category(8325)|| post_is_in_descendant_category( '8325' )) {
$cat_name = 'リネレボ攻略';
}else{
$category = get_the_category();
$cat_name = $category[0]->cat_name;
}
$seph = '【';
$sepb = '】';
$rsstitlehead = $cat_name;
$title = $seph . $rsstitlehead . $sepb . $title;
return $title;
}else{
$title = $title;
return $title;
}
}
add_filter( 'the_title_rss', 'cat_added_title');
function feed_content_remove_class_adsense_top($content) {
return preg_replace('/ class="adsense_top"/', '', $content);
}
add_filter('the_excerpt_rss', 'feed_content_remove_class_adsense_top');
add_filter('the_content_feed', 'feed_content_remove_class_adsense_top');
/* YARPP CSS無効 */
//ヘッダー部分のCSS消去
add_action('wp_print_styles','lm_dequeue_header_styles');
function lm_dequeue_header_styles(){ wp_dequeue_style('yarppWidgetCss'); }
//フッター部分のCSS消去
add_action('get_footer','lm_dequeue_footer_styles');
function lm_dequeue_footer_styles(){ wp_dequeue_style('yarppRelatedCss'); }
//サムネイルを有効にした場合に呼び出されるCSS消去
add_action('wp_print_styles','lm_dequeue_header_styles1');
function lm_dequeue_header_styles1(){ wp_dequeue_style('yarpp-thumbnails-yarpp-thumbnail'); }
add_action('get_footer','lm_dequeue_footer_styles1');
function lm_dequeue_footer_styles1(){ wp_dequeue_style('yarpp-thumbnails-yarpp-thumbnail'); }
// iframe の埋め込み許可(管理者・編集者相当のみ)
add_filter( 'content_save_pre', 'sqool_allow_iframe_for_trusted_roles' );
function sqool_allow_iframe_for_trusted_roles( $content ) {
if ( ! current_user_can( 'edit_others_posts' ) && ! current_user_can( 'manage_options' ) ) {
return $content;
}
global $allowedposttags;
$allowedposttags['iframe'] = array(
'class' => array(),
'src' => array(),
'width' => array(),
'height' => array(),
'frameborder' => array(),
'scrolling' => array(),
'marginheight' => array(),
'marginwidth' => array(),
'allow' => array(),
'allowfullscreen' => array(),
'loading' => array(),
'referrerpolicy' => array(),
);
return $content;
}
/* 文字列変換解除 */
// 高速化目的での無効化は副作用が大きいためコメントアウト(過去記事の表記揺れ・崩れの原因になる)
// 特定テンプレートでのみ無効化が必要な場合は、対象テンプレート限定で実装する
// remove_filter('the_content', 'wptexturize'); // wptexturizeによる文字列変換をしない
// remove_filter('the_content', 'convert_chars'); // convert_charsによる文字列変換をしない
/* wp-headerからGoogle Fontsを削除 */
function google_fonts_dequeue() {
wp_dequeue_style('sqool-fonts');
}
add_action( 'wp_enqueue_scripts', 'google_fonts_dequeue', 10);
/* 記事タイトル引用文字数制限 */
function titlelimitchar($title){
if(mb_strlen($title) > 65 && !(is_single()) && !(is_page()) && !(is_feed())){
$title = mb_substr($title,0,65) . "…";
}
return $title;
}
add_filter( 'the_title', 'titlelimitchar' );
/* カスタムCSS欄 */
add_action('admin_menu', 'custom_css_hooks');
add_action('save_post', 'save_custom_css');
add_action('wp_head','insert_custom_css');
function custom_css_hooks() {
$post_types = sqool_get_post_types();
foreach ( $post_types as $post_type ) {
add_meta_box( 'custom_css', 'カスタムCSS', 'custom_css_input', $post_type, 'normal', 'high' );
}
}
function custom_css_input() {
global $post;
echo '<input type="hidden" name="custom_css_noncename" id="custom_css_noncename" value="'.wp_create_nonce('custom-css').'" />';
echo '<textarea name="custom_css" id="custom_css" rows="5" cols="30" style="width:100%;">'.get_post_meta($post->ID,'_custom_css',true).'</textarea>';
}
function save_custom_css($post_id) {
// 配列キーの存在チェックを追加(エラー防止)
if (!isset($_POST['custom_css_noncename']) || !wp_verify_nonce($_POST['custom_css_noncename'], 'custom-css')) return $post_id;
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return $post_id;
if (!isset($_POST['custom_css'])) return $post_id;
$custom_css = $_POST['custom_css'];
update_post_meta($post_id, '_custom_css', $custom_css);
}
/**
* CSS向けの最小サニタイズ(esc_html()の代替)
* esc_html()はCSS構文(>や&など)を壊すため、危険な要素のみを削除
*/
if ( ! function_exists('sqool_sanitize_css') ) {
function sqool_sanitize_css( $css ) {
if ( ! is_string( $css ) ) {
return '';
}
// 危険な要素を削除(</style>タグや<script>タグ)
$css = preg_replace( '#</?style[^>]*>#i', '', $css );
$css = preg_replace( '#<script[^>]*>.*?</script>#is', '', $css );
// HTMLコメントを削除(<!-- -->)
$css = preg_replace( '#<!--.*?-->#s', '', $css );
return $css;
}
}
function insert_custom_css() {
if ( ! is_page() && ! is_single() ) {
return;
}
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return;
}
$custom_css = get_post_meta( $post_id, '_custom_css', true );
if ( $custom_css ) {
// CSS向けの最小サニタイズを使用(esc_html()はCSS構文を壊すため使用しない)
$sanitized_css = sqool_sanitize_css( $custom_css );
echo '<style type="text/css">' . $sanitized_css . '</style>';
}
}
/* Ver4.8用 ウィジェットに勝手にbrやpが入るのをブロック */
remove_filter('widget_text_content', 'wpautop');
/* ------------------------------------------------------------------------- *
* カスタムタクソノミー追加
/* ------------------------------------------------------------------------- */
/* 脱出ゲームテーマ */
function add_custom_taxonomies() {
$labels = array(
'name' => _x( 'テーマ別脱出ゲーム', 'taxonomy general name' ),
'singular_name' => _x( 'テーマ別脱出ゲーム', 'taxonomy singular name' ),
'search_items' => __( 'テーマを探す' ),
'popular_items' => __( 'ポピュラーなテーマ' ),
'all_items' => __( '全てのテーマ' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'テーマを編集' ),
'update_item' => __( 'テーマをアップデート' ),
'add_new_item' => __( 'テーマを新しく追加' ),
'new_item_name' => __( '新たなテーマの名前' ),
'separate_items_with_commas' => __( 'コンマで区切ってください' ),
'add_or_remove_items' => __( 'テーマの追加または削除' ),
'choose_from_most_used' => __( '最も使用しているテーマ' )
);
register_taxonomy(
'escape-theme',
array('post','hints-and-tips'),
array(
'public' => true,
'show_ui' => true,
'hierarchical' => false,
'labels' => $labels,
'query_var' => true,
'rewrite' => true,
'show_tagcloud' => true
)
);
}
add_action('init', 'add_custom_taxonomies', 0);
function add_custom_taxonomies_2() {
/* 攻略ゲームタイトル */
$labels = array(
'name' => _x( '攻略ゲームタイトル', 'taxonomy general name' ),
'singular_name' => _x( '攻略ゲームタイトル', 'taxonomy singular name' ),
'search_items' => __( '攻略ゲームタイトルを選ぶ' ),
'popular_items' => __( 'よく使う攻略ゲームタイトル' ),
'all_items' => __( '全てのタイトル' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( '攻略ゲームタイトルを編集' ),
'update_item' => __( '攻略ゲームタイトルをアップデート' ),
'add_new_item' => __( '攻略ゲームタイトルを新しく追加' ),
'new_item_name' => __( '新たな攻略ゲームタイトル名' ),
'separate_items_with_commas' => __( 'コンマで区切ってください' ),
'add_or_remove_items' => __( '攻略ゲームタイトルの追加または削除' ),
'choose_from_most_used' => __( '最も使用している攻略ゲームタイトル' )
);
register_taxonomy(
'game-title',
array('post','page','business','businessnews','column','esports','news','blog','travel','review','report','special','hints-and-tips','premium'),
array(
'public' => true,
'show_ui' => true,
'hierarchical' => true,
'labels' => $labels,
'query_var' => true,
'rewrite' => array(
'slug' => 'hints-and-tips',
'with_front' => false,
'hierarchical' => false
),
'show_tagcloud' => true
)
);
}
add_action('init', 'add_custom_taxonomies_2', 0);
function add_custom_taxonomies_3() {
/* 外部配信キーワード */
$labels = array(
'name' => _x( '配信キーワード', 'taxonomy general name' ),
'singular_name' => _x( '配信キーワード', 'taxonomy singular name' ),
'search_items' => __( '配信キーワードを選ぶ' ),
'popular_items' => __( 'よく使う配信キーワード' ),
'all_items' => __( '全てのタイトル' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( '配信キーワードを編集' ),
'update_item' => __( '配信キーワードをアップデート' ),
'add_new_item' => __( '配信キーワードを新しく追加' ),
'new_item_name' => __( '新たな配信キーワード' ),
'separate_items_with_commas' => __( 'コンマで区切ってください' ),
'add_or_remove_items' => __( '配信キーワードの追加または削除' ),
'choose_from_most_used' => __( '最も使用している配信キーワード' )
);
register_taxonomy(
'delivery-keyword',
array('post','page','business','businessnews','column','esports','news','dreamnews','prwire','robot','blog','travel','review','report','special','hints-and-tips','premium'),
array(
'public' => true,
'show_ui' => true,
'hierarchical' => true,
'labels' => $labels,
'query_var' => true,
'rewrite' => true,
'show_tagcloud' => true
)
);
}
add_action('init', 'add_custom_taxonomies_3', 0);
function add_custom_taxonomies_4() {
/* eスポーツタイトル */
$labels = array(
'name' => _x( 'eスポーツタイトル', 'taxonomy general name' ),
'singular_name' => _x( 'eスポーツタイトル', 'taxonomy singular name' ),
'search_items' => __( 'eスポーツタイトルを選ぶ' ),
'popular_items' => __( 'よく使うeスポーツタイトル' ),
'all_items' => __( '全てのeスポーツタイトル' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'eスポーツタイトルを編集' ),
'update_item' => __( 'eスポーツタイトルをアップデート' ),
'add_new_item' => __( 'eスポーツタイトルを新しく追加' ),
'new_item_name' => __( '新たなeスポーツタイトル' ),
'separate_items_with_commas' => __( 'コンマで区切ってください' ),
'add_or_remove_items' => __( 'eスポーツタイトルの追加または削除' ),
'choose_from_most_used' => __( '最も使用しているeスポーツタイトル' )
);
register_taxonomy(
'esports-title',
array('post','page','business','businessnews','column','esports','news','robot','blog','travel','review','report','special','hints-and-tips','premium'),
array(
'public' => true,
'show_ui' => true,
'hierarchical' => true,
'labels' => $labels,
'query_var' => true,
'rewrite' => true,
'show_tagcloud' => true
)
);
}
add_action('init', 'add_custom_taxonomies_4', 0);
function add_custom_taxonomies_5() {
/* 脱出ゲームタイトル */
$labels = array(
'name' => _x( '脱出ゲームタイトル', 'taxonomy general name' ),
'singular_name' => _x( '脱出ゲームタイトル', 'taxonomy singular name' ),
'search_items' => __( '脱出ゲームタイトルを選ぶ' ),
'popular_items' => __( 'よく使う脱出ゲームタイトル' ),
'all_items' => __( '全ての脱出タイトル' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( '脱出ゲームタイトルを編集' ),
'update_item' => __( '脱出ゲームタイトルをアップデート' ),
'add_new_item' => __( '脱出ゲームタイトルを新しく追加' ),
'new_item_name' => __( '新たな脱出ゲームタイトル名' ),
'separate_items_with_commas' => __( 'コンマで区切ってください' ),
'add_or_remove_items' => __( '脱出ゲームタイトルの追加または削除' ),
'choose_from_most_used' => __( '最も使用している脱出ゲームタイトル' )
);
register_taxonomy(
'escape-game-title',
array('post','page','business','businessnews','column','esports','news','blog','travel','review','report','special','hints-and-tips'),
array(
'public' => true,
'show_ui' => true,
'hierarchical' => true,
'labels' => $labels,
'query_var' => true,
'rewrite' => true,
'show_tagcloud' => true
)
);
}
add_action('init', 'add_custom_taxonomies_5', 0);
/* ------------------------------------------------------------------------- *
* コメントアバター追加
/* ------------------------------------------------------------------------- */
function tty_addgravatar( $avatar_defaults ) {
$myavatar = get_bloginfo('url') . '/pic/g_avatar_3.png';
$avatar_defaults[$myavatar] = 'ゲスト';
return $avatar_defaults;
}
add_filter( 'avatar_defaults', 'tty_addgravatar' );
/* 固定ページのURL末尾にスラッシュを付ける */
function add_slash_uri_end( $uri, $type ) {
// .html で終わるURLは末尾スラッシュを絶対に付けない(/foo.html/ を防止)
if ( is_string( $uri ) && preg_match( '#\.html/?$#i', $uri ) ) {
return preg_replace( '#/+$#', '', $uri );
}
// single 以外は従来どおり末尾スラッシュ
if ( $type !== 'single' ) {
$uri = trailingslashit( $uri );
}
return $uri;
}
add_filter('user_trailingslashit', 'add_slash_uri_end', 10, 2);
/* ------------------------------------------------------------------------- *
* コメント欄クッキー保存コメント変更
/* ------------------------------------------------------------------------- */
function comment_form_cookies_msg_4536($arg) {
if(function_exists('wp_get_current_commenter')) $commenter = wp_get_current_commenter();
$consent = empty( $commenter['comment_author_email'] ) ? '' : ' checked="checked"';
$title = '名前を保存する。'; // 自由に変更可能
$arg['cookies'] = '<p class="comment-form-cookies-consent">'.
'<input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"'.$consent.' />'.
'<label for="wp-comment-cookies-consent">'.$title.'</label></p>';
return $arg;
}
add_filter( 'comment_form_default_fields', 'comment_form_cookies_msg_4536' );
/* -------------------------------------------------------------------------
* 安全なunserialize処理関数(汎用版)
* 壊れたシリアライズデータでもエラーを出さずにfalseを返す
* FeedWordPressブロックの外に定義(コメント添付などでも使用するため)
* ------------------------------------------------------------------------- */
if ( ! function_exists('sqool_safe_unserialize') ) {
function sqool_safe_unserialize( $data ) {
// 既に配列やオブジェクトの場合はそのまま返す
if ( is_array( $data ) || is_object( $data ) ) {
return $data;
}
// nullやfalse、空文字列の場合はfalseを返す
if ( empty( $data ) || ! is_string( $data ) ) {
return false;
}
// シリアライズされていない場合はfalseを返す
if ( ! function_exists( 'is_serialized' ) || ! is_serialized( $data ) ) {
return false;
}
// エラーハンドラーを一時的に設定して、unserialize()のエラーを完全にキャッチ
// 他のエラーは触らない(最小構成でunserialize警告だけ握る)
$previous_error_handler = set_error_handler( function( $errno, $errstr, $errfile, $errline ) use ( &$previous_error_handler ) {
// unserialize()関連のエラーのみをキャッチ(再発耐性を上げるため、Error at offsetに限定せずunserialize()全般に対応)
if ( ( $errno === E_WARNING || $errno === E_NOTICE )
&& strpos( $errstr, 'unserialize()' ) !== false ) {
return true; // unserialize()関連のエラーを抑制
}
// それ以外のエラーは元のハンドラーに渡す(触らない)
if ( $previous_error_handler !== null ) {
return call_user_func( $previous_error_handler, $errno, $errstr, $errfile, $errline );
}
// ハンドラーがない場合はデフォルト動作に任せる
return false;
}, E_WARNING | E_NOTICE );
// unserializeを実行(エラーが発生しても抑制される)
// @は使わず、エラーハンドラーに完全に任せる
$result = unserialize( $data );
// エラーハンドラーを復元(確実に元に戻す)
restore_error_handler();
// 失敗した場合(falseが返され、かつ元のデータがfalseのシリアライズでない場合)はfalseを返す
if ( $result === false ) {
// 元のデータが false のシリアライズ("b:0;")かどうかを確認
// 静的変数でキャッシュして毎回serialize()しないように最適化
static $serialized_false = null;
if ( $serialized_false === null ) {
$serialized_false = serialize( false );
}
if ( $data !== $serialized_false ) {
// falseのシリアライズでない場合は失敗として扱う
return false;
}
}
return $result;
}
}
/* -------------------------------------------------------------------------
* コメントへの画像添付(comment-attachment代替/補完)
* 目的:
* - comment-attachment プラグインのPHP警告(Undefined array key等)が原因で管理画面/フロントが重くなる場合でも
* コメント添付機能を維持できるようにする。
* 方針:
* - フォームに file input を追加
* - 送信時に wp_handle_upload / media_handle_upload でアップロード
* - comment_meta に attachment_id を保存
* - 表示時に comment_text の末尾へ添付画像を差し込む
*
* 注意:
* - まずは安全側(画像のみ、サイズ制限あり)
* - 既存プラグインを残す場合でも、この実装だけで最低限の添付は動く
* ------------------------------------------------------------------------- */
// 設定(必要なら調整)
if ( ! defined( 'SQOOL_COMMENT_ATTACH_MAX_BYTES' ) ) {
define( 'SQOOL_COMMENT_ATTACH_MAX_BYTES', 3 * 1024 * 1024 ); // 3MB
}
// comment form を multipart にする(ファイル送信のため)
// NOTE: comment_form_defaults の 'form' を直接書き換えるとテーマ/環境によって効かないことがあるため、
// 出力される <form> タグ自体をフィルタして確実に付与する。
add_filter( 'comment_form_tag', function( $form_tag ) {
if ( strpos( $form_tag, 'enctype=' ) !== false ) {
return $form_tag;
}
return str_replace( '<form', '<form enctype="multipart/form-data"', $form_tag );
} );
// フォームに添付フィールドとnonceを追加(ログイン/未ログイン両対応)
function sqool_comment_attachment_field() {
// コメントが閉じている/対象外の画面では何もしない
if ( ! is_singular() || ! comments_open() ) {
return;
}
// 画像添付フィールド
echo '<p class="comment-form-attachment" style="margin-top:12px;">';
echo '<label for="sqool_comment_attachment">画像を添付(任意)</label><br />';
echo '<input type="file" id="sqool_comment_attachment" name="sqool_comment_attachment" accept="image/*" />';
echo '</p>';
// nonce
wp_nonce_field( 'sqool_comment_attachment', 'sqool_comment_attachment_nonce' );
}
add_action( 'comment_form_after_fields', 'sqool_comment_attachment_field' );
add_action( 'comment_form_logged_in_after', 'sqool_comment_attachment_field' );
// バリデーション(サイズ/拡張子)
add_filter( 'preprocess_comment', function( $commentdata ) {
if ( empty( $_FILES['sqool_comment_attachment'] ) ) {
return $commentdata;
}
if ( ! isset( $_POST['sqool_comment_attachment_nonce'] ) || ! wp_verify_nonce( $_POST['sqool_comment_attachment_nonce'], 'sqool_comment_attachment' ) ) {
// コメント本文は受け付け、添付だけ無視する(UX悪化とDoSリスクを避ける)
unset( $_FILES['sqool_comment_attachment'] );
return $commentdata;
}
$f = $_FILES['sqool_comment_attachment'];
// エラー無し以外は無視
if ( ! isset( $f['error'] ) || (int) $f['error'] !== UPLOAD_ERR_OK ) {
return $commentdata;
}
// サイズ制限(違反時は添付だけ破棄、コメントは通す)
if ( isset( $f['size'] ) && (int) $f['size'] > SQOOL_COMMENT_ATTACH_MAX_BYTES ) {
// wp_die()ではなく、添付ファイルだけ破棄してコメント投稿を続行(DoS耐性・UX向上)
unset( $_FILES['sqool_comment_attachment'] );
return $commentdata;
}
// MIME/拡張子制限(画像のみ)(違反時は添付だけ破棄、コメントは通す)
$check = wp_check_filetype_and_ext( $f['tmp_name'], $f['name'] );
$allowed_mimes = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp' );
if ( empty( $check['type'] ) || ! in_array( $check['type'], $allowed_mimes, true ) ) {
// wp_die()ではなく、添付ファイルだけ破棄してコメント投稿を続行(DoS耐性・UX向上)
unset( $_FILES['sqool_comment_attachment'] );
return $commentdata;
}
return $commentdata;
} );
// コメント保存後にアップロード処理して comment_meta に attachment_id を保存
add_action( 'comment_post', function( $comment_id ) {
if ( empty( $_FILES['sqool_comment_attachment'] ) ) {
return;
}
if ( ! isset( $_POST['sqool_comment_attachment_nonce'] ) || ! wp_verify_nonce( $_POST['sqool_comment_attachment_nonce'], 'sqool_comment_attachment' ) ) {
return;
}
$f = $_FILES['sqool_comment_attachment'];
if ( ! isset( $f['error'] ) || (int) $f['error'] !== UPLOAD_ERR_OK ) {
return;
}
// media_handle_upload を使うために必要
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
// コメントに紐づける親は存在しないので 0(必要なら投稿IDにしても良い)
$attachment_id = media_handle_upload( 'sqool_comment_attachment', 0 );
if ( is_wp_error( $attachment_id ) ) {
// ここで wp_die するとコメント自体は既に保存済みなので、致命停止は避ける
// エラーログに記録(デバッグ用)
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( 'SQOOL Comment Attachment Error: ' . $attachment_id->get_error_message() . ' (Comment ID: ' . $comment_id . ')' );
}
return;
}
add_comment_meta( $comment_id, 'sqool_comment_attachment_id', (int) $attachment_id, true );
}, 10, 1 );
// 互換: comment-attachment 等の既存プラグインが保存していた comment_meta をできるだけ拾って表示する
function sqool_get_comment_attachment_html( $comment_id ) {
$comment_id = (int) $comment_id;
if ( $comment_id <= 0 ) {
return '';
}
// 共通: 画像HTML生成(attachment ID から)
$sqool_render_attachment_id = function( $attachment_id ) {
$attachment_id = (int) $attachment_id;
if ( $attachment_id <= 0 ) {
return '';
}
$img = wp_get_attachment_image( $attachment_id, 'medium', false, array(
'class' => 'sqool-comment-attachment',
'loading' => 'lazy',
'decoding' => 'async',
) );
if ( $img ) {
return '<div class="sqool-comment-attachment-wrap" style="margin-top:10px;">' . $img . '</div>';
}
return '';
};
// 共通: 画像HTML生成(URL から)
$sqool_render_image_url = function( $url ) {
if ( ! is_string( $url ) ) {
return '';
}
$vv = trim( $url );
if ( $vv === '' ) {
return '';
}
if ( preg_match( '#^https?://#i', $vv ) ) {
$ext = strtolower( pathinfo( parse_url( $vv, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
$allowed_ext = array( 'jpg', 'jpeg', 'png', 'gif', 'webp' );
if ( in_array( $ext, $allowed_ext, true ) ) {
return '<div class="sqool-comment-attachment-wrap" style="margin-top:10px;">'
. '<img class="sqool-comment-attachment" loading="lazy" decoding="async" src="' . esc_url( $vv ) . '" alt="" />'
. '</div>';
}
}
return '';
};
// 共通: uploads のファイルパス / 相対パスをURLに解決して表示
$sqool_render_uploads_path = function( $path_or_url ) use ( $sqool_render_image_url ) {
if ( ! is_string( $path_or_url ) ) {
return '';
}
$v = trim( $path_or_url );
if ( $v === '' ) {
return '';
}
// すでにURLならそのまま
if ( preg_match( '#^https?://#i', $v ) ) {
return $sqool_render_image_url( $v );
}
$uploads = wp_upload_dir();
$baseurl = isset( $uploads['baseurl'] ) ? $uploads['baseurl'] : '';
$basedir = isset( $uploads['basedir'] ) ? $uploads['basedir'] : '';
if ( ! $baseurl || ! $basedir ) {
return '';
}
// (A) 絶対パスが uploads 配下
if ( strpos( $v, $basedir ) === 0 ) {
$rel = ltrim( str_replace( $basedir, '', $v ), '/' );
return $sqool_render_image_url( trailingslashit( $baseurl ) . $rel );
}
// (B) /wp-content/uploads/... 形式
if ( strpos( $v, '/wp-content/uploads/' ) !== false ) {
$pos = strpos( $v, '/wp-content/uploads/' );
$rel = substr( $v, $pos + strlen( '/wp-content/uploads/' ) );
$rel = ltrim( $rel, '/' );
return $sqool_render_image_url( trailingslashit( $baseurl ) . $rel );
}
// (C) uploads配下の相対パスのみ(例: 2018/03/foo.jpg)
if ( preg_match( '#^\d{4}/\d{2}/#', $v ) ) {
return $sqool_render_image_url( trailingslashit( $baseurl ) . ltrim( $v, '/' ) );
}
return '';
};
// 共通: 値から添付を推定して表示(ID / URL / 配列 / シリアライズ文字列 / パス)
// NOTE: 再帰(配列/ネスト構造)を扱うため、クロージャを参照渡しでuseする
$sqool_try_render_from_value = null;
$sqool_try_render_from_value = function( $val ) use ( &$sqool_try_render_from_value, $sqool_render_attachment_id, $sqool_render_image_url, $sqool_render_uploads_path ) {
if ( empty( $val ) ) {
return '';
}
// シリアライズ文字列は展開(安全に処理)
if ( is_string( $val ) && function_exists( 'is_serialized' ) && is_serialized( $val ) ) {
$un = sqool_safe_unserialize( $val );
if ( $un !== false && $un !== $val ) {
$val = $un;
}
}
// 数値(attachment ID の可能性)
if ( is_numeric( $val ) ) {
return $sqool_render_attachment_id( (int) $val );
}
// URL
if ( is_string( $val ) ) {
$h = $sqool_render_image_url( $val );
if ( $h ) {
return $h;
}
// ファイルパス/相対パス
$h = $sqool_render_uploads_path( $val );
if ( $h ) {
return $h;
}
}
// 配列(プラグイン実装差異)
if ( is_array( $val ) ) {
$keys = array(
'attachment_id',
'id',
'file_id',
'url',
'file',
'path',
'guid',
);
foreach ( $keys as $k ) {
if ( isset( $val[ $k ] ) ) {
$h = $sqool_try_render_from_value( $val[ $k ] );
if ( $h ) {
return $h;
}
}
}
// それ以外: 配列を総当りで探索
foreach ( $val as $vv ) {
$h = $sqool_try_render_from_value( $vv );
if ( $h ) {
return $h;
}
}
}
return '';
};
// 1) このfunctions.php実装のメタ(推奨)
$attachment_id = (int) get_comment_meta( $comment_id, 'sqool_comment_attachment_id', true );
if ( $attachment_id > 0 ) {
$h = $sqool_render_attachment_id( $attachment_id );
if ( $h ) {
return $h;
}
}
// 2) 旧プラグイン互換(まずは「よくある」キーを優先探索)
$legacy_keys = array(
'comment_attachment_id',
'comment-attachment',
'comment_attachment',
'attachment_id',
'_attachment_id',
'_comment_attachment_id',
'comment_attachment_url',
'attachment_url',
'comment_attachment_file',
'attachment_file',
'ca_attachment_id',
'ca_attachment',
'comment_attachment_meta',
);
foreach ( $legacy_keys as $k ) {
$v = get_comment_meta( $comment_id, $k, true );
$h = $sqool_try_render_from_value( $v );
if ( $h ) {
return $h;
}
}
// 全メタ走査は削除(根本解決: 壊れたserializedデータを踏んでエラーを量産しないため)
// 互換性は legacy_keys の範囲に限定し、総当り探索は行わない
// 見つからなかった場合は空を返す
return '';
}
// 表示: コメント本文末尾に添付画像を差し込む(新実装 + 旧プラグイン互換)
add_filter( 'comment_text', function( $comment_text, $comment = null ) {
// $commentがオブジェクトでない場合は、グローバルから取得を試みる
if ( empty( $comment ) || ! is_object( $comment ) ) {
global $comment;
if ( empty( $comment ) || empty( $comment->comment_ID ) ) {
return $comment_text;
}
}
if ( empty( $comment->comment_ID ) ) {
return $comment_text;
}
// この実装が既に添付画像を差し込んだかどうかを判定(sqool-comment-attachment-wrapクラスで判断)
// <img> タグの存在ではなく、この実装が生成したマーカーで判定することで、他のプラグインや絵文字による誤判定を回避
if ( strpos( $comment_text, 'sqool-comment-attachment-wrap' ) !== false ) {
return $comment_text;
}
$attach_html = sqool_get_comment_attachment_html( $comment->comment_ID );
if ( ! $attach_html ) {
return $comment_text;
}
return $comment_text . $attach_html;
}, 20, 2 );
/* 管理メニューバーがずれるのを修正 */
// TODO: 将来的にはCSSファイル側へ寄せる(毎回インラインCSSを吐くのはノイズになり得る)
function oz_admin_bar_to_the_bottom() {
if (wp_is_mobile()) {
echo '<style type="text/css">
#wpadminbar{
margin-top:0;
position: fixed;
z-index: 999999999999;
}
</style>';
}else{
echo '<style type="text/css">
#wpadminbar{
margin-top:34px;
position: fixed;
z-index: 999999999999;
}
</style>';
}
}
add_action( 'wp_head', 'oz_admin_bar_to_the_bottom' );
/* カスタム投稿タイプを追加 */
add_action( 'init', 'create_post_type' );
function create_post_type() {
// カスタム投稿タイプの定義を配列で管理
$post_types = array(
'column' => array(
'name' => 'コラム',
'slug' => 'column/archive',
'has_archive' => true
),
'news' => array(
'name' => 'ニュース',
'slug' => 'news/archive',
'has_archive' => true
),
'dreamnews' => array(
'name' => 'ドリームニュース',
'slug' => 'news/dreamnews/archive',
'has_archive' => true
),
'prwire' => array(
'name' => 'PRワイヤー',
'slug' => 'news/prwire/archive',
'has_archive' => true
),
'esports' => array(
'name' => 'eスポーツ',
'slug' => 'esports/archive',
'has_archive' => true
),
'business' => array(
'name' => 'ビジネス',
'slug' => 'business/archive',
'has_archive' => true
),
'businessnews' => array(
'name' => 'ビジネスニュース',
'slug' => 'business/news/archive',
'has_archive' => true
),
'robot' => array(
'name' => 'ロボット',
'slug' => 'robot/archive',
'has_archive' => true
),
'blog' => array(
'name' => 'ブログ',
'slug' => 'blog/archive',
'has_archive' => true
),
'travel' => array(
'name' => '旅行',
'slug' => 'travel/archive',
'has_archive' => true
),
'review' => array(
'name' => 'レビュー',
'slug' => 'review/archive',
'has_archive' => true
),
'report' => array(
'name' => '取材',
'slug' => 'report/archive',
'has_archive' => true
),
'notice' => array(
'name' => 'お知らせ',
'slug' => 'notice/archive',
'has_archive' => true
),
'link' => array(
'name' => 'リンクページ',
'slug' => 'link/archive',
'has_archive' => true
),
'special' => array(
'name' => '特設',
'slug' => 'special/archive',
'has_archive' => true
),
'hints-and-tips' => array(
'name' => 'ゲーム攻略',
'slug' => 'hints-and-tips',
'has_archive' => false
),
'premium' => array(
'name' => 'プレミアム',
'slug' => 'premium/archive',
'has_archive' => false
)
);
// 共通設定
$common_supports = array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'custom-fields', 'trackbacks', 'comments', 'revisions' );
$post_type_keys = array_keys( $post_types );
// ループで登録
foreach ( $post_types as $post_type => $args ) {
register_post_type( $post_type, array(
'labels' => array(
'name' => __( $args['name'] ),
'singular_name' => __( $args['name'] )
),
'public' => true,
'has_archive' => $args['has_archive'],
'menu_position' => 5,
'supports' => $common_supports,
'rewrite' => array( 'slug' => $args['slug'], 'with_front' => false ),
'yarpp_support' => true
) );
}
// カスタム投稿タイプカテゴリとタグ共用
foreach ( $post_type_keys as $post_type ) {
register_taxonomy_for_object_type( 'category', $post_type );
register_taxonomy_for_object_type( 'post_tag', $post_type );
}
}
/* -------------------------------------------------------------------------
* CPT「日付-投稿ID.html」形式のシングルURLを確実に解決するためのリライトルール
* 目的:
* - /news/archive/20251219-535416.html を single に解決
* - 末尾スラッシュ付与(.html/)や archive への丸め込みを防ぐ
* 対象:
* - news, dreamnews, prwire, businessnews
* ------------------------------------------------------------------------- */
// 1) ルール追加(.htmlあり/なし、末尾スラッシュあり/なしに対応)
function sqool_add_cpt_html_rewrite_rules() {
// news
add_rewrite_rule( '^news/archive/(\d{8})-(\d+)\.html/?$', 'index.php?post_type=news&p=$matches[2]', 'top' );
add_rewrite_rule( '^news/archive/(\d{8})-(\d+)/?$', 'index.php?post_type=news&p=$matches[2]', 'top' );
// dreamnews
add_rewrite_rule( '^news/dreamnews/archive/(\d{8})-(\d+)\.html/?$', 'index.php?post_type=dreamnews&p=$matches[2]', 'top' );
add_rewrite_rule( '^news/dreamnews/archive/(\d{8})-(\d+)/?$', 'index.php?post_type=dreamnews&p=$matches[2]', 'top' );
// prwire
add_rewrite_rule( '^news/prwire/archive/(\d{8})-(\d+)\.html/?$', 'index.php?post_type=prwire&p=$matches[2]', 'top' );
add_rewrite_rule( '^news/prwire/archive/(\d{8})-(\d+)/?$', 'index.php?post_type=prwire&p=$matches[2]', 'top' );
// businessnews
add_rewrite_rule( '^business/news/archive/(\d{8})-(\d+)\.html/?$', 'index.php?post_type=businessnews&p=$matches[2]', 'top' );
add_rewrite_rule( '^business/news/archive/(\d{8})-(\d+)/?$', 'index.php?post_type=businessnews&p=$matches[2]', 'top' );
}
add_action( 'init', 'sqool_add_cpt_html_rewrite_rules', 20 );
// notice アーカイブを /notice/ にも対応させる(リンク先と実際のアーカイブスラッグの不一致を吸収)
function sqool_add_notice_archive_alias_rules() {
// /notice/ を notice アーカイブに解決
add_rewrite_rule( '^notice/?$', 'index.php?post_type=notice', 'top' );
// /notice/page/2/ などのページングにも対応
add_rewrite_rule( '^notice/page/([0-9]{1,})/?$', 'index.php?post_type=notice&paged=$1', 'top' );
}
add_action( 'init', 'sqool_add_notice_archive_alias_rules', 20 );
// report アーカイブを /report/ にも対応させる(リンク先と実際のアーカイブスラッグの不一致を吸収)
function sqool_add_report_archive_alias_rules() {
// /report/ を report アーカイブに解決
add_rewrite_rule( '^report/?$', 'index.php?post_type=report', 'top' );
// /report/page/2/ などのページングにも対応
add_rewrite_rule( '^report/page/([0-9]{1,})/?$', 'index.php?post_type=report&paged=$1', 'top' );
}
add_action( 'init', 'sqool_add_report_archive_alias_rules', 20 );
// 上記ルールを確実に反映させるため、一度だけリライトルールをフラッシュ
function sqool_maybe_flush_rewrite_once_for_notice_alias() {
$ver = get_option( 'sqool_notice_alias_rules_v1', '' );
if ( $ver === '1' ) {
return;
}
update_option( 'sqool_notice_alias_rules_v1', '1', false );
flush_rewrite_rules( false );
}
add_action( 'admin_init', 'sqool_maybe_flush_rewrite_once_for_notice_alias' );
// report アーカイブのリライトルールを確実に反映させるため、一度だけリライトルールをフラッシュ
function sqool_maybe_flush_rewrite_once_for_report_alias() {
$ver = get_option( 'sqool_report_alias_rules_v1', '' );
if ( $ver === '1' ) {
return;
}
update_option( 'sqool_report_alias_rules_v1', '1', false );
flush_rewrite_rules( false );
}
add_action( 'admin_init', 'sqool_maybe_flush_rewrite_once_for_report_alias' );
// game-title タクソノミーのリライトルールを確実に反映させるため、一度だけリライトルールをフラッシュ
function sqool_maybe_flush_rewrite_once_for_game_title_taxonomy() {
$ver = get_option( 'sqool_game_title_taxonomy_rewrite_v1', '' );
if ( $ver === '1' ) {
return;
}
update_option( 'sqool_game_title_taxonomy_rewrite_v1', '1', false );
flush_rewrite_rules( false );
}
add_action( 'admin_init', 'sqool_maybe_flush_rewrite_once_for_game_title_taxonomy' );
// hints-and-tips 固定ページのリライトルールを確実に反映させるため、一度だけリライトルールをフラッシュ
function sqool_maybe_flush_rewrite_once_for_hints_and_tips_page() {
$ver = get_option( 'sqool_hints_and_tips_page_rewrite_v1', '' );
if ( $ver === '1' ) {
return;
}
update_option( 'sqool_hints_and_tips_page_rewrite_v1', '1', false );
flush_rewrite_rules( false );
}
add_action( 'admin_init', 'sqool_maybe_flush_rewrite_once_for_hints_and_tips_page' );
// hints-and-tips の固定ページを優先的に認識させる(game-titleタクソノミーとの競合を回避)
// request フィルタで固定ページを優先
function sqool_prioritize_hints_and_tips_page( $query_vars ) {
// 管理画面やフィードの場合は処理しない
if ( is_admin() || ( defined( 'DOING_CRON' ) && DOING_CRON ) ) {
return $query_vars;
}
// game-title タクソノミーが既に設定されている場合
if ( isset( $query_vars['game-title'] ) ) {
$term_slug = $query_vars['game-title'];
// 固定ページとして存在するかチェック
$page = get_page_by_path( 'hints-and-tips/' . $term_slug );
if ( $page && $page->post_status === 'publish' ) {
// 固定ページが存在する場合は、タクソノミーのクエリを削除して固定ページとして処理
unset( $query_vars['game-title'] );
unset( $query_vars['taxonomy'] );
unset( $query_vars['term'] );
$query_vars['pagename'] = 'hints-and-tips/' . $term_slug;
}
}
return $query_vars;
}
add_filter( 'request', 'sqool_prioritize_hints_and_tips_page', 1 );
// 2) .html系URLの canonical redirect を抑止(/foo.html/ 誘導や archive への丸め込みを防ぐ)
function sqool_disable_canonical_for_cpt_html( $redirect_url, $requested_url ) {
$path = '';
if ( is_string( $requested_url ) && $requested_url !== '' ) {
$pp = wp_parse_url( $requested_url );
$path = isset( $pp['path'] ) ? $pp['path'] : '';
}
if ( $path === '' ) {
return $redirect_url;
}
if ( preg_match( '#^/news/archive/\d{8}-\d+\.html/?$#', $path )
|| preg_match( '#^/news/dreamnews/archive/\d{8}-\d+\.html/?$#', $path )
|| preg_match( '#^/news/prwire/archive/\d{8}-\d+\.html/?$#', $path )
|| preg_match( '#^/business/news/archive/\d{8}-\d+\.html/?$#', $path )
) {
return false;
}
return $redirect_url;
}
add_filter( 'redirect_canonical', 'sqool_disable_canonical_for_cpt_html', 10, 2 );
// 3) リライトルールのフラッシュを「一度だけ」実行(パーマリンク画面が死ぬ場合の救済)
function sqool_maybe_flush_rewrite_once_for_cpt_html() {
$ver = get_option( 'sqool_cpt_html_rules_v1', '' );
if ( $ver === '1' ) {
return;
}
update_option( 'sqool_cpt_html_rules_v1', '1', false );
flush_rewrite_rules( false ); // .htaccess は触らない
}
add_action( 'admin_init', 'sqool_maybe_flush_rewrite_once_for_cpt_html' );
/* カテゴリ一覧にカスタム投稿タイプ追加*/
add_action('pre_get_posts', 'show_categorized_pages_in_archive');
function show_categorized_pages_in_archive( $query ) {
if ( $query->is_category && $query->is_main_query() ) {
$query->set( 'post_type', sqool_get_post_types() );
}
}
/* タグ一覧にカスタム投稿タイプ追加*/
add_action('pre_get_posts', 'show_taged_pages_in_archive');
function show_taged_pages_in_archive( $query ) {
if ( $query->is_tag && $query->is_main_query() ) {
$query->set( 'post_type', sqool_get_post_types() );
}
}
/* カスタム投稿タイプRSS統合 */
function mysite_feed_request( $vars ) {
if ( isset( $vars['feed'] ) && ! isset( $vars['post_type'] ) ) {
$vars['post_type'] = sqool_get_post_types();
}
return $vars;
}
add_filter( 'request', 'mysite_feed_request' );
/* ショートコード設定開始 */
//吹き出し
function bubble_left_img($atts, $content = null )
{
//初期設定
extract(shortcode_atts(array(
'id' =>'3',
'align' =>'left',
'imgurl' =>'none',
'speaker' =>'none'
), $atts));
//違う画像を表示したかったら
if ($imgurl == 'none'){
$img = get_avatar_url($id);
}
else {
$img = $imgurl;
}
//メンバー以外の名前を表示したかったら
if($speaker == 'none'){
$author = get_the_author_meta('nickname', $id);
}
else {
$author = $speaker;
}
//無理やりhtmlを生成
$bubble_html='<div class="balloon-box balloon-'.$align.' clrfix">
<div class="balloon-icon"><img src="'. $img .'"><br><span>'. $author .'</span></div>
<div class="balloon-serif"><div class="balloon-content">'. $content .'</div></div>
</div>';
return $bubble_html;
}
add_shortcode('bubble', 'bubble_left_img');
//白黒のSNSボタン
function shortcode2() {
ob_start();
get_template_part('/shortcorde/sns_channel');
return ob_get_clean();
}
add_shortcode('sns_channel', 'shortcode2');
//攻略記事ファーストビュー
function shortcode3() {
global $post;
ob_start();
$isAmp = (wp_is_mobile() && isset($_GET['amp']) && $_GET['amp'] == 1) ? true : false;
if($isAmp){
echo('<div class="headleft1">');
echo('<div class="article_top_img">');
$thumbnail_id = get_post_thumbnail_id();
$thumbnail_img = wp_get_attachment_image_src( $thumbnail_id , 'thumb150_113' );
echo('<amp-img src="');
echo $thumbnail_img[0];
echo('" width="121" height="97"></amp-img>');
echo('</div>');
echo('<div style="line-height:1.4; ">');
if ( has_excerpt( $post->ID ) ) {
the_excerpt();
}
echo('</div>');
echo('<div class="clear"></div>');
}else{
echo('<div style="width:100%;margin-top:5px;">');
echo('<div style="width:30%; float:left;margin-right:5px;" class="article_top_img">');
the_post_thumbnail('thumb150_113');
echo('</div>');
echo('<div style="line-height:1.4; ">');
if ( has_excerpt( $post->ID ) ) {
the_excerpt();
}
echo('</div>');
echo('<div class="clear"></div>');
}
return ob_get_clean();
}
add_shortcode('image_left_text_right', 'shortcode3');
//パシリン
function shortcode4() {
ob_start();
if (wp_is_mobile()) {
echo(' <a href="https://sqool.net/ninja-pasirin"><img src="https://sqool.net/wp-content/uploads/2015/12/600_200_title_banner02.jpg" alt="" width="600" height="200" /></a> ');
}else{
echo(' <a href="https://sqool.net/ninja-pasirin"><img src="https://sqool.net/wp-content/uploads/2015/12/600_200_title_banner02-500x167.jpg" alt="" width="300px" height="100" /></a> ');
}
return ob_get_clean();
}
add_shortcode('pasirin_bana', 'shortcode4');
//パズドラ攻略コーナー
function shortcode_pazudora_menu() {
ob_start();
if (file_exists(get_template_directory() . '/shortcorde/pazudora_menu.php')) {
include(get_template_directory() . '/shortcorde/pazudora_menu.php');
} else {
echo '<p>メニューが現在利用できません。</p>';
}
return ob_get_clean();
}
add_shortcode('pazudora_menu', 'shortcode_pazudora_menu');
//検索ボックス
function shortcode6() {
ob_start();
get_search_form();
return ob_get_clean();
}
add_shortcode('get_search_form', 'shortcode6');
//更新日
function shortcode8() {
ob_start();
the_modified_date('Y年n月j日');
return ob_get_clean();
}
add_shortcode('updated', 'shortcode8');
//黒ウィズ攻略コーナー
function shortcode10() {
ob_start();
get_template_part('/shortcorde/wiz_menu');
return ob_get_clean();
}
add_shortcode('wiz_menu', 'shortcode10');
//FFRK攻略コーナー
function shortcode11() {
ob_start();
get_template_part('/shortcorde/ffrk_menu');
return ob_get_clean();
}
add_shortcode('ffrk_menu', 'shortcode11');
//DQMSL攻略コーナー
function shortcode12() {
ob_start();
get_template_part('/shortcorde/dqmsl_menu');
return ob_get_clean();
}
add_shortcode('dqmsl_menu', 'shortcode12');
//グラブル攻略コーナー
function shortcode14() {
ob_start();
get_template_part('/shortcorde/guraburu_menu');
return ob_get_clean();
}
add_shortcode('guraburu_menu', 'shortcode14');
//モンスト攻略コーナー
function shortcode15() {
ob_start();
get_template_part('/shortcorde/monst_menu');
return ob_get_clean();
}
add_shortcode('monst_menu', 'shortcode15');
//おすすめ検索ワードあり検索ボックス
function shortcode16() {
ob_start();
get_template_part('/shortcorde/search_option');
return ob_get_clean();
}
add_shortcode('search_option', 'shortcode16');
//攻略タイトル一覧
function shortcode17() {
ob_start();
get_template_part('/shortcorde/cheats-list');
return ob_get_clean();
}
add_shortcode('cheats-list', 'shortcode17');
//サイトマップページ
function shortcode18() {
ob_start();
get_template_part('/shortcorde/sitemap');
return ob_get_clean();
}
add_shortcode('sitemap', 'shortcode18');
//脱出ゲーム攻略メニュー
function shortcode19() {
ob_start();
get_template_part('/shortcorde/escape_menu');
return ob_get_clean();
}
add_shortcode('escape_menu', 'shortcode19');
//トップページ全コード
function shortcode20() {
ob_start();
get_template_part('/shortcorde/top_page');
return ob_get_clean();
}
add_shortcode('top_page', 'shortcode20');
//ニュースメニュー
function shortcode21() {
ob_start();
get_template_part('/shortcorde/news_menu');
return ob_get_clean();
}
add_shortcode('news_menu', 'shortcode21');
//攻略メニュー
function shortcode22() {
ob_start();
get_template_part('/shortcorde/how_to_play_menu');
return ob_get_clean();
}
add_shortcode('how_to_play_menu', 'shortcode22');
//脱出ゲームのタイトル語尾
function shortcode23() {
ob_start();
if(in_category(24)|| post_is_in_descendant_category( '24' )) {
$etitle = get_the_title();
if(strstr($etitle,"脱出")==false){
echo('|脱出ゲーム攻略');
}
}
return ob_get_clean();
}
add_shortcode('title_after', 'shortcode23');
//タイトル語頭
function shortcode24() {
ob_start();
if(in_category(array('10','93','96','247','896','63','3334','6053','1693','789','2043','3548','4400','3558','4482','4639','7484','7657' ) )) {
$category = get_the_category(); $cat_name = $category[0]->cat_name;
echo('【'); echo $cat_name; echo('】');
}elseif ( in_category( '24' ) || post_is_in_descendant_category( '24' ) ) {
if(has_tag('脱出ゲームタイトルページ')){
echo('脱出ゲーム ');
}
}elseif ( in_category(array('4183','4786')) ) { echo('【モンスト】');
}elseif ( in_category(array('8325')) ) { echo('【リネレボ】');
}elseif ( in_category( '4591' ) || post_is_in_descendant_category( '4591' ) ) {
if ( has_term( 'pokemori', 'game-title' ) ) {
echo('【ポケ森】');
}
}
return ob_get_clean();
}
add_shortcode('title_head', 'shortcode24');
//鍵付きのユーザー投稿型
function shortcode25() {
ob_start();
get_template_part('/shortcorde/news_post_lock');
return ob_get_clean();
}
add_shortcode('news_post_lock', 'shortcode25');
//3秒後にトップページに移動
function shortcode26() {
ob_start();
if (!wp_is_mobile()){ echo(' <meta http-equiv="Refresh" content="2, https://sqool.net/" />このページはスマートフォン専用です。<br>3秒後にトップページに移動します。<br>自動的に移動しない場合は下のリンクをクリックしてください。<br><a href="https://sqool.net/">https://sqool.net/</a><br><br><img src="https://sqool.net/pic/404.png"> '); }
return ob_get_clean();
}
add_shortcode('notpc', 'shortcode26');
//ゲーム動画コーナー
function shortcode27() {
ob_start();
get_template_part('/shortcorde/game_movie_menu');
return ob_get_clean();
}
add_shortcode('game_movie_menu', 'shortcode27');
//スマホ ページ上部のMORE
function shortcode28() {
ob_start();
get_template_part('/shortcorde/corner_top_menu');
return ob_get_clean();
}
add_shortcode('corner_top_menu', 'shortcode28');
//新着脱出ゲーム 開発者投稿
function shortcode29() {
ob_start();
get_template_part('/shortcorde/escape_release');
return ob_get_clean();
}
add_shortcode('escape_release', 'shortcode29');
//新着脱出ゲーム 開発者投稿 一覧
function shortcode30() {
ob_start();
get_template_part('/shortcorde/escape_release_list');
return ob_get_clean();
}
add_shortcode('escape_release_list', 'shortcode30');
//カテゴリ内最終更新日
function shortcode31() {
ob_start();
get_template_part('/shortcorde/lastmodified');
return ob_get_clean();
}
add_shortcode('lastmodified', 'shortcode31');
//new_article_escape_n
function shortcode32() {
ob_start();
get_template_part('/shortcorde/new_article_escape_n');
return ob_get_clean();
}
add_shortcode('new_article_escape_n', 'shortcode32');
//全記事リスト PC左カラム用 脱出個別記事排除
function shortcode33() {
ob_start();
get_template_part('/shortcorde/menu_list_format_pl_alllist');
return ob_get_clean();
}
add_shortcode('menu_list_format_pl_alllist', 'shortcode33');
//各記事の下 新着記事一覧へのリンクボタン
function shortcode34() {
ob_start();
get_template_part('/shortcorde/content_under_allmenu');
return ob_get_clean();
}
add_shortcode('content_under_allmenu', 'shortcode34');
//画像付きテーブル
function shortcode35($atts) {
extract(shortcode_atts(array(
'tagname' => '',
'exclude' => '',
'order' => '',
'orderby' => '',
'list_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/matome_page.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('matome_page', 'shortcode35');
//ナビ有りリスト
function shortcode36($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_n.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_n', 'shortcode36');
//ナビ無しリスト
function shortcode37($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format', 'shortcode37');
//ナビ無しリスト
function shortcode38($atts) {
extract(shortcode_atts(array(
'page_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_pl_alllist_n.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_pl_alllist_n', 'shortcode38');
//menu_paged_p
function shortcode39($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'page_number' => '',
'offsetno' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_p.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_p', 'shortcode39');
//記事一覧 投稿タイプでフィルター
function shortcode40($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => '',
'post_type_name' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_post_type_n.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_post_type_n', 'shortcode40');
//シンプルな2列の記事一覧
function shortcode41($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'offsetno' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged', 'shortcode41');
//一部で使われている1列の記事一覧
function shortcode42($atts) {
extract(shortcode_atts(array(
'menu_tag' => '',
'list_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/tag_menu.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('tag_menu', 'shortcode42');
//カテゴリ・タグ連結・日付アリ・ナビ無し・目次記事用【AかつB】
function shortcode44($atts) {
extract(shortcode_atts(array(
'menu_cat_1' => '',
'menu_tag' => '',
'pagenumber' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_cat_tag_n_s.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_cat_tag_n_s', 'shortcode44');
//脱出ゲーム各タイトルのトップページ 同開発者の他のゲーム
function shortcode45($atts) {
extract(shortcode_atts(array(
'tagname' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/escape_top_developer.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('escape_top_developer', 'shortcode45');
//テーマ別脱出ゲーム一覧
function shortcode46($atts) {
extract(shortcode_atts(array(
'order' => '',
'orderby' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/escape_theme_list.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('escape_theme_list', 'shortcode46');
//開発者が投稿した脱出ゲームの一覧
function shortcode47($atts) {
extract(shortcode_atts(array(
'post_no' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/escape_release_new.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('escape_release_new', 'shortcode47');
//おすすめ脱出ゲームページ(開発者別ページ)
function shortcode48($atts) {
extract(shortcode_atts(array(
'tagname' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/escape_recommend_page.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('escape_recommend_page', 'shortcode48');
//パズドラテンプレパのパネル
function shortcode49($atts) {
extract(shortcode_atts(array(
'monster' => '',
'text' => '',
'order' => '',
'orderby' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/pazudora_template.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('pazudora_template', 'shortcode49');
//パズドラテンプレパのパネル(評価記事orテンプレパがない時用)
function shortcode50($atts) {
extract(shortcode_atts(array(
'monster' => '',
'text' => '',
'image' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/pazudora_template_2.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('pazudora_template_2', 'shortcode50');
//パズドラテンプレパ 属性別 おすすめ度別 一覧
function shortcode51($atts) {
extract(shortcode_atts(array(
'tagname' => '',
'orderby' => '',
'key' => '',
'value' => '',
'exclude' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/pazudora_template_list.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('pazudora_template_list', 'shortcode51');
//menu_list_format_pn(右サイドバーで使用中)
function shortcode52($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_pn.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_pn', 'shortcode52');
//menu_list_format_pl(左サイドバーで使用中【お知らせ】)
function shortcode53($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_pl.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_pl', 'shortcode53');
//左右2枠 タグ用
function shortcode54($atts) {
extract(shortcode_atts(array(
'tagname' => '',
'page_no' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_tag.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_tag', 'shortcode54');
//記事下 記事一覧 投稿タイプでフィルター
function shortcode55($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => '',
'post_type_name' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_post_type.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_post_type', 'shortcode55');
//記事下 記事一覧 投稿タイプでフィルター(AMP)
function shortcode56($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'list_number' => '',
'post_type_name' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_post_type_amp.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_post_type_amp', 'shortcode56');
//カテゴリとタグのOR結合メニュー ナビ無し
function shortcode57($atts) {
extract(shortcode_atts(array(
'menu_cat_1' => '',
'menu_tag' => '',
'pagenumber' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_cat_tag_n.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_cat_tag_n', 'shortcode57');
//カテゴリとタグのOR結合メニュー ナビ無し(AMP)
function shortcode58($atts) {
extract(shortcode_atts(array(
'menu_cat_1' => '',
'menu_tag' => '',
'pagenumber' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_cat_tag_n_amp.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_cat_tag_n_amp', 'shortcode58');
//指定した数だけ大きい画像など(注目)
function shortcode59($atts) {
extract(shortcode_atts(array(
'notable_cat' => '',
'notable_tag' => '',
'notable_page' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/notable_list.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('notable_list', 'shortcode59');
//カテゴリ+ゲームタイトルでの記事リスト 左右2枠
function shortcode60($atts) {
extract(shortcode_atts(array(
'menu_cat' => '',
'game_title' => '',
'pagenumber' => '16'
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_game_title.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_game_title', 'shortcode60');
//アーカイブページ コンテンツ下 記事一覧
function shortcode61($atts) {
extract(shortcode_atts(array(
'post_type' => '',
'notable_page' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/notable_1.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('notable_1', 'shortcode61');
//ビジネス記事一覧リスト
function shortcode62($atts) {
extract(shortcode_atts(array(
'list_number' => '',
'post_type_name' => 'business', // デフォルト値を設定
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_post_type_n_business.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_post_type_n_business', 'shortcode62');
//eスポーツ記事一覧リスト
function shortcode63($atts) {
extract(shortcode_atts(array(
'list_number' => '',
'post_type_name' => 'esports', // デフォルト値を設定
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_list_format_post_type_n_esports.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_list_format_post_type_n_esports', 'shortcode63');
//ドリームニュース
function shortcode64() {
ob_start();
get_template_part('/shortcorde/menu_paged_dreamnews');
return ob_get_clean();
}
add_shortcode('menu_paged_dreamnews', 'shortcode64');
//PRワイヤー
function shortcode65() {
ob_start();
get_template_part('/shortcorde/menu_paged_prwire');
return ob_get_clean();
}
add_shortcode('menu_paged_prwire', 'shortcode65');
//攻略タイトル記事リスト
function shortcode66($atts) {
extract(shortcode_atts(array(
'menu_title' => '',
'offsetno' => ''
), $atts));
ob_start();
include(locate_template( '/shortcorde/menu_paged_gametitle.php' ));
$output = ob_get_clean();
return $output;
}
add_shortcode('menu_paged_gametitle', 'shortcode66');
//ヤスヒロ攻略コーナー
function shortcode13() {
ob_start();
get_template_part('/shortcorde/yasuhiro_menu');
return ob_get_clean();
}
add_shortcode('yasuhiro_menu', 'shortcode13');
/* ショートコード設定ここまで */
/* Smart News */
add_action( 'do_feed_smartnews', 'do_feed_smartnews' );
function do_feed_smartnews() {
$feed_template = get_template_directory() . '/smartnews.php';
load_template( $feed_template );
}
/* Smart News test */
add_action( 'do_feed_smartnews_test', 'do_feed_smartnews_test' );
function do_feed_smartnews_test() {
$feed_template = get_template_directory() . '/smartnews_test.php';
load_template( $feed_template );
}
/* LINE News */
add_action( 'do_feed_linerss', 'do_feed_linerss' );
function do_feed_linerss() {
$feed_template = get_template_directory() . '/linerss.php';
load_template( $feed_template );
}
/* LINE News_test */
add_action( 'do_feed_linerss_test', 'do_feed_linerss_test' );
function do_feed_linerss_test() {
$feed_template = get_template_directory() . '/linerss_test.php';
load_template( $feed_template );
}
// RSSフィードから除くものを指定 ※カスタムフィールドによりRSS除外とするための設定
function exclude_tag_rss($query) {
if ($query->is_feed) {
$query->set('meta_query',
array(
array(
'key'=>'exclusion_from_wprss',
'compare' => 'NOT EXISTS'
),
array(
'key'=>'exclusion_from_wprss',
'value'=>'1',
'compare'=>'!='
),
'relation'=>'OR'
)
);
}
}
add_filter('pre_get_posts', 'exclude_tag_rss');
// RSSの本文から不要な属性を削除
function feed_content_remove_class($content) {
return preg_replace('/ (class|style|alt|itemprop)="(.*?)"/', '', $content);
}
add_filter('the_excerpt_rss', 'feed_content_remove_class');
add_filter('the_content_feed', 'feed_content_remove_class');
/* 画像キャプション使用時のHTMLタグ変更 */
add_shortcode('caption', 'my_img_caption_shortcode');
function my_img_caption_shortcode($attr, $content = null) {
if ( ! isset( $attr['caption'] ) ) {
if ( preg_match( '#((?:<a [^>]+>s*)?<img [^>]+>(?:s*</a>)?)(.*)#is', $content, $matches ) ) {
$content = $matches[1];
$attr['caption'] = trim( $matches[2] );
}
}
$output = apply_filters('img_caption_shortcode', '', $attr, $content);
if ( $output != '' )
return $output;
extract(shortcode_atts(array(
'id' => '',
'align' => 'alignnone',
'width' => '',
'caption' => ''
), $attr, 'caption'));
if ( 1 > (int) $width || empty($caption) )
return $content;
if ( $id ) $id = 'id="' . esc_attr($id) . '" ';
return '<p>' . do_shortcode( $content ) . '<aside class="wp-caption-text">▲' . $caption . '</aside></p>';
}
/*画像キャプションを無効化する*/
add_filter( 'disable_captions', '__return_true' );
function my_gallery_default_type_set_link( $settings ) {
$settings['galleryDefaults']['link'] = 'none';
$settings['galleryDefaults']['columns'] = '2';
$settings['galleryDefaults']['size'] = 'medium';
return $settings;
}
add_filter( 'media_view_settings', 'my_gallery_default_type_set_link');
/* 管理画面のメディア一覧: 月別フィルタ(年/月ドロップダウン) を無効化
* 目的: attachment の YEAR/MONTH DISTINCT 集計クエリを抑止して管理画面負荷を下げる
* 影響: メディア一覧の月別絞り込みUIが消えるだけ。アップロードURLの /yyyy/mm/ 構造は変更されない。
*/
// upload.php の一覧テーブル(WP_List_Table::months_dropdown)を完全に無効化(UI表示もクエリも止める)
add_filter( 'disable_months_dropdown', function( $disable, $post_type ) {
if ( 'attachment' === $post_type ) {
return true;
}
return $disable;
}, 10, 2 );
// 念のため: months_dropdown のDBクエリをショートサーキット(disable_months_dropdownが効かない環境向け)
add_filter( 'pre_months_dropdown_query', function( $months, $post_type ) {
if ( 'attachment' === $post_type ) {
return array();
}
return $months;
}, 10, 2 );
// メディアモーダル(添付ファイル選択UI)側の月別フィルタ生成も停止
add_filter( 'media_library_months_with_files', '__return_empty_array' );
/* 管理画面のメディア一覧: 種別フィルタ(画像/動画/音声など)の生成を抑止
* 目的: get_available_post_mime_types() の DISTINCT post_mime_type クエリを抑止して負荷を下げる
* 影響: upload.php の「すべてのメディア」ドロップダウン(種別絞り込み)が実質無効化されるだけ。
*/
add_filter( 'get_available_post_mime_types', function( $mimes, $type ) {
if ( is_admin() && 'attachment' === $type ) {
return array(); // 抽出クエリ回避
}
return $mimes;
}, 10, 2 );
//空白のaltに記事タイトルを設定する
function change_any_texts($text){
$img_post_title = get_the_title();
$replace = array(
'alt=""' => 'alt="'.$img_post_title.'"'
);
$text = str_replace(array_keys($replace), $replace, $text);
return $text;
}
add_filter('the_content', 'change_any_texts');
// Customize YouTube oEmbed Code - 遅延読み込みで最適化
function custom_youtube_oembed($code){
if(strpos($code, 'youtu.be') !== false || strpos($code, 'youtube.com') !== false){
// パラメータを追加して遅延読み込みを有効化
$html = preg_replace("@src=(['\"])?([^'\">\s]*)@", "src=$1$2&showinfo=0&rel=0&loading=lazy", $code);
$html = preg_replace('/ width="\d+"/', '', $html);
$html = preg_replace('/ height="\d+"/', '', $html);
// loading="lazy"属性を追加(iframeが存在する場合)
if (strpos($html, '<iframe') !== false) {
$html = preg_replace('/<iframe/', '<iframe loading="lazy"', $html);
}
$html = '<div class="youtube">' . $html . '</div>';
return $html;
}
return $code;
}
add_filter('embed_handler_html', 'custom_youtube_oembed');
add_filter('embed_oembed_html', 'custom_youtube_oembed');
/* Public Post Previewの有効期限延長 */
add_filter( 'ppp_nonce_life', 'my_nonce_life' );
function my_nonce_life() {
return 60 * 60 * 24 * 7;// 7 日間(秒×分×時間×日)
}
/* 表示オプションにカスタムフィールドを表示 */
// ACF側の「WP標準カスタムフィールドを消す」設定を有効化(標準UI削除の方針と整合性を取る)
add_filter('acf/settings/remove_wp_meta_box', '__return_true');
//コメントが許可されているか
function is_comment_open(){
global $post;
if ( isset($post->comment_status) ) {
return $post->comment_status == 'open';
}
return false;
}
//はてぶ風ブログカード(リンクカード)生成
//サイトドメインを取得
function get_this_site_domain(){
//ドメイン情報を$results[1]に取得する
preg_match( '/https?:\/\/(.+?)\//i', admin_url(), $results );
return $results[1];
}
//本文抜粋を取得する関数(綺麗な抜粋文を作成するため)
//使用方法:http://nelog.jp/get_the_custom_excerpt
function get_the_custom_excerpt($content, $length) {
$length = ($length ? $length : 70);//デフォルトの長さを指定する
$content = preg_replace('/<!--more-->.+/is',"",$content); //moreタグ以降削除
$content = strip_shortcodes($content);//ショートコード削除
$content = strip_tags($content);//タグの除去
$content = str_replace(" ","",$content);//特殊文字の削除(今回はスペースのみ)
$content = mb_substr($content,0,$length);//文字列を指定した長さで切り取る
return $content;
}
//本文中のURLをブログカードタグに変更する
function url_to_blog_card($the_content) {
// キャッシュキーを生成(同じコンテンツの再処理を防ぐ)
static $processed_content = array();
$content_hash = md5($the_content);
if (isset($processed_content[$content_hash])) {
return $processed_content[$content_hash];
}
// 処理回数を制限(無限ループ防止)
static $process_count = 0;
if ($process_count > 10) {
$processed_content[$content_hash] = $the_content;
return $the_content;
}
$process_count++;
if ( is_singular() ) {//投稿ページもしくは固定ページのとき
//1行にURLのみが期待されている行(URL)を全て$mに取得
$res = preg_match_all('/^(<p>)?(<a.+?>)?https?:\/\/'.preg_quote(get_this_site_domain()).'\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+\$,%#]+(<\/a>)?(<\/p>)?(<br ? \/>)?$/im', $the_content,$m);
// マッチしたURLが多すぎる場合は処理をスキップ(パフォーマンス保護)
if (count($m[0]) > 5) {
$processed_content[$content_hash] = $the_content;
return $the_content;
}
// 投稿IDのキャッシュ(同じリクエスト内での重複クエリを防ぐ)
static $url_to_id_cache = array();
//マッチしたURL一つ一つをループしてカードを作成
foreach ($m[0] as $match) {
$url = strip_tags($match);//URL
// キャッシュから投稿IDを取得
if (!isset($url_to_id_cache[$url])) {
$url_to_id_cache[$url] = url_to_postid( $url );
}
$id = $url_to_id_cache[$url];
if ( !$id ) continue;//IDを取得できない場合はループを飛ばす
// 投稿情報のキャッシュ
static $post_cache = array();
if (!isset($post_cache[$id])) {
$post_cache[$id] = get_post($id);
}
$post = $post_cache[$id];
if ( !$post ) continue;
$title = $post->post_title;//タイトルの取得
$date = mysql2date('Y-m-d H:i', $post->post_date);//投稿日の取得
$excerpt = get_the_custom_excerpt($post->post_content, 90);//抜粋の取得
$thumbnail = get_the_post_thumbnail($id, 'thumb100', array('style' => 'width:100px;height:100px;', 'class' => 'blog-card-thumb-image'));//サムネイルの取得(要100×100のサムネイル設定)
if ( !$thumbnail ) {//サムネイルが存在しない場合
$thumbnail = '<img src="'.get_template_directory_uri().'/images/no-image.png" style="width:100px;height:100px;" />';
}
//取得した情報からブログカードのHTMLタグを作成
$tag = '<div class="blog-card"><div class="blog-card-thumbnail"><a href="'.$url.'" class="blog-card-thumbnail-link">'.$thumbnail.'</a></div><div class="blog-card-content"><div class="blog-card-title"><a href="'.$url.'" class="blog-card-title-link">'.$title.'</a></div><div class="blog-card-excerpt">'.$excerpt.'</div></div><div class="blog-card-footer clear"><span class="blog-card-date">'.$date.'</span></div></div>';
//本文中のURLをブログカードタグで置換
$the_content = preg_replace('{'.preg_quote($match).'}', $tag , $the_content, 1);
}
}
// 処理結果をキャッシュ
$processed_content[$content_hash] = $the_content;
return $the_content;//置換後のコンテンツを返す
}
add_filter('the_content','url_to_blog_card');//本文表示をフック
//oembed無効
add_filter( 'embed_oembed_discover', '__return_false' );
//Embeds
remove_action( 'parse_query', 'wp_oembed_parse_query' );
remove_action( 'wp_head', 'wp_oembed_remove_discovery_links' );
remove_action( 'wp_head', 'wp_oembed_remove_host_js' );
//Wordpress4.5.3でポスト時に再び表示されるようになってしまったので対処
remove_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result');
//line rss
function line_rss($content, $del_url) {
//linerssの為の処理
$regexp = '/\<aside id=\"linerss\"\>[\s\S]*?\<\/aside\>/';
$content2 = preg_replace($regexp, '', $content);
//特定のURLを削除(アフィリエイト、ストアへの誘導系)
foreach($del_url as $key => $value) {
if ($value) {
$value2 = str_replace("/", "\/", $value);
$regexp2 = '/\<h2\>.*\<\/h2\>\n\<p\>\<a href=\"' . $value2 . '.*\<\/a\>\<\/p\>/';
$content2 = preg_replace($regexp2, '', $content2);
$regexp2 = '/\<a href=\"' . $value2 . '.*\<\/a\>/';
$content2 = preg_replace($regexp2, '', $content2);
}
}
//lineurlで囲われたの以外 <a helfのタグを消す テキストは残す
//一旦 lineurlのタグを特殊なものに置き換え
$content2_2 = str_replace("<aside id=\"lineurl\"><a href=", "[lineurl]", $content2);
$content2_3 = str_replace("</a></aside>", "[/lineurl]", $content2_2);
//ダウンロード削除
$regexp5 = '/\<h2\>.*ダウンロード.*\<\/h2\>\n\<div[\s\S]*?\<\/ul\>\n\<\/div\>/';
$content2_4 = preg_replace($regexp5, '', $content2_3);
//Aタグを 全て消してみる
$regexp3 = '/\<a href=\".+\"\>/';
$content3 = preg_replace($regexp3, '', $content2_4);
$regexp4 = '/\<\/a\>/';
$content4 = preg_replace($regexp4, '(※リンクは省略しています)', $content3);
//lineurlのタグを戻す
$content4_2 = str_replace("[lineurl]", "<a href=", $content4);
$content4_3 = str_replace("[/lineurl]", "</a>", $content4_2);
// echo $content4_3;
return $content4_3;
}
// フッター用スクリプトを読み込み(最適化版)
if ( ! is_admin() ) {
function sqool_enqueue_footer_scripts() {
wp_enqueue_script(
'sqool-footer-scripts',
get_template_directory_uri() . '/js/footer-scripts.js',
array(), // jQuery依存を削除
'1.0.1', // バージョン更新(最適化版)
true // フッター読み込み
);
// テーマディレクトリのURLをJavaScript変数として出力
wp_localize_script('sqool-footer-scripts', 'sqoolTheme', array(
'jsUrl' => get_template_directory_uri() . '/js/'
));
}
add_action('wp_enqueue_scripts', 'sqool_enqueue_footer_scripts', 20);
// 非クリティカルなスクリプトにdefer属性を付与
function sqool_add_defer_to_scripts( $tag, $handle, $src ) {
// 除外リスト(同期読み込みが必要なスクリプト)
$excluded = array(
'jquery',
'jquery-core',
'jquery-migrate',
'comment-reply',
'clipboard.min.js'
);
// navigation.jsはdeferで読み込む(メインスレッドのブロックを防止)
if ( $handle === 'sqool-navigation' ) {
return str_replace( ' src', ' defer src', $tag );
}
// 除外リストに含まれていないスクリプトにdeferを追加
foreach ( $excluded as $exclude ) {
if ( strpos( $handle, $exclude ) !== false || strpos( $src, $exclude ) !== false ) {
return $tag;
}
}
// defer属性を追加
return str_replace( ' src', ' defer src', $tag );
}
add_filter( 'script_loader_tag', 'sqool_add_defer_to_scripts', 10, 3 );
}
///////////////////////////////////////////////////////////////////////////////////////////////
//プレスリリースの掲載の通知系
///////////////////////////////////////////////////////////////////////////////////////////////
add_action( 'admin_init', 'pr_mail_init' );
function pr_mail_init() {
$post_types = sqool_get_post_types();
//投稿ページ サイドバー
add_meta_box( 'pr_mail_side_post', 'プレスリリースの掲載の通知', 'pr_mail_side', $post_types, 'side' );
//投稿ページ
add_meta_box( 'pr_mail_post', 'プレスリリースの掲載の通知 メール入力', 'pr_mail', $post_types );
}
//プレスリリースの掲載の通知 サイド
function pr_mail_side( $param ) {
global $wpdb; //データベースを触るためのおまじない
global $post;
echo '<div id="js-list-pr-mail"></div><br><input type="hidden" name="pr_mail_flg" id="pr_mail_flg" value="" /><button id="pr_mail_btn"> 送信 </button><BR>';
// テーブルが存在するかチェック(エラーを抑制してチェック)
$table_name = $wpdb->prefix . 'mail_history';
$wpdb->suppress_errors( true );
$table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
$wpdb->suppress_errors( false );
if ( $table_exists ) {
$get_data = $wpdb->get_results( $wpdb->prepare(
"SELECT mail, send_date FROM {$wpdb->prefix}mail_history WHERE post_id = %d AND type = 0 ORDER BY send_date DESC LIMIT 3",
$post->ID
) );
// エラーが発生した場合は無視(テーブルが存在しない場合など)
if ( $wpdb->last_error ) {
$wpdb->last_error = ''; // エラーをクリア
} elseif ( $get_data ) {
foreach ( $get_data as $d ) {
echo "<BR><b>・" . esc_html( $d->mail ) . "</b><BR> (" . esc_html( $d->send_date ) . ")";
}
}
}
}
//プレスリリースの掲載の通知
function pr_mail( $param ) {
//sqool用のグローバルデータ群
require("inc/global.php");
global $post;
//メールの記事URLの部分を置き換える
$pr_mail_txt2 = str_replace('<pr_mail_txt>', esc_url(get_permalink()), $pr_mail_txt);
// $paramは投稿情報
echo '<input type="hidden" id="pr_mail_title" value="' . $pr_mail_title . '***' . $post->ID . '" />';
echo 'メールアドレス:<input type="text" id="pr_mail_email" size="40" value="" /><BR>';
echo '<textarea id="pr_mail_txt" rows="10" cols="120">' . $pr_mail_txt2 . '</textarea>';
}
//プレスリリースの掲載のメール送るためのAJAX設定
function ajax_pr_mail_scripts($hook_suffix) {
// 投稿編集画面(post.php/post-new.php)かつ対象投稿タイプのみ読み込む
$screen = get_current_screen();
if (!$screen || !in_array($screen->base, ['post', 'post-new'], true)) return;
if (!in_array($screen->post_type, sqool_get_post_types(), true)) return;
$handle = 'pr_mail';
$file = get_template_directory_uri() . '/js/' . $handle . '.js';
wp_register_script( $handle, $file, array( 'jquery' ) );
$action = 'pr-mail-action';
wp_localize_script($handle, 'PR_MAIL_AJAX', [
'api' => admin_url('admin-ajax.php'),
'action' => $action,
'nonce' => wp_create_nonce($action)
]);
wp_enqueue_script($handle);
}
add_action('admin_enqueue_scripts', 'ajax_pr_mail_scripts');
//プレスリリースの掲載のメール送る コールバック
function ajax_pr_mail_call () {
//sqool用のグローバルデータ群
require("inc/global.php");
global $wpdb; //データベースを触るためのおまじない
$action = 'pr-mail-action';
$data = '';
if(check_ajax_referer($action, 'nonce', false)) {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title_and_id = $_POST["pr_mail_title"];
$email = $_POST["pr_mail_email"];
$info = $_POST["pr_mail_info"];
$headers = [];
$headers[] = 'From: ' . $pr_to_mail[0];
//タイトルと記事IDに分ける
$title_and_id2 = explode("***",$title_and_id);
$title = $title_and_id2[0];
$post_id = $title_and_id2[1];
//メール送信
wp_mail($email, $title, $info, $headers, "");
//DBに保存(テーブルが存在する場合のみ)
$table_name = $wpdb->prefix . 'mail_history';
$wpdb->suppress_errors( true );
$table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
$wpdb->suppress_errors( false );
if ( $table_exists ) {
$wpdb->insert(
$wpdb->prefix . 'mail_history',
array( 'post_id' => $post_id, 'mail' => $email, 'type' => 0 ),
array( '%d', '%s', '%d' )
);
// エラーが発生した場合は無視
if ( $wpdb->last_error ) {
$wpdb->last_error = '';
}
}
status_header('200');
$data = 'OK';
}
}
else {
status_header('403');
$data = 'Forbidden';
}
header('Content-Type: application/json; charset=UTF-8');
echo $data;
die();
}
add_action('wp_ajax_pr-mail-action', 'ajax_pr_mail_call');
add_action('wp_ajax_nopriv_pr-mail-action', 'ajax_pr_mail_call');
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
//記事連携の通知系
///////////////////////////////////////////////////////////////////////////////////////////////
add_action('admin_init', 'link_mail_init');
function link_mail_init() {
$post_types = sqool_get_post_types();
//投稿ページ サイドバー
add_meta_box( 'link_mail_side_post', '記事連携の通知', 'link_mail_side', $post_types, 'side' );
//投稿ページ
add_meta_box( 'link_mail_post', '記事連携の通知 メール入力', 'link_mail', $post_types );
}
//記事連携の通知 サイド
function link_mail_side( $param ) {
global $wpdb; //データベースを触るためのおまじない
global $post;
echo '<div id="js-list-link-mail"></div><br><input type="hidden" name="link_mail_flg" id="link_mail_flg" value="" /><button id="link_mail_btn"> 送信 </button><BR>';
// テーブルが存在するかチェック(エラーを抑制してチェック)
$table_name = $wpdb->prefix . 'mail_history';
$wpdb->suppress_errors( true );
$table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
$wpdb->suppress_errors( false );
if ( $table_exists ) {
$get_data = $wpdb->get_results( $wpdb->prepare(
"SELECT send_date FROM {$wpdb->prefix}mail_history WHERE post_id = %d AND type = 1 ORDER BY send_date DESC LIMIT 3",
$post->ID
) );
// エラーが発生した場合は無視(テーブルが存在しない場合など)
if ( $wpdb->last_error ) {
$wpdb->last_error = ''; // エラーをクリア
} elseif ( $get_data ) {
foreach ( $get_data as $d ) {
echo "<BR><b>・送信しました!</b><BR> (" . esc_html( $d->send_date ) . ")";
}
}
}
}
//記事連携の通知
function link_mail( $param ) {
//sqool用のグローバルデータ群
require("inc/global.php");
global $post;
//メールの記事URLの部分を置き換える
$link_mail_txt2 = str_replace('<link_mail_txt>', esc_url(get_permalink()), $link_mail_txt);
// $paramは投稿情報
echo '<input type="hidden" id="link_mail_title" value="' . $link_mail_title . '***' . $post->ID . '" />';
echo '<textarea id="link_mail_txt" rows="10" cols="120">' . $link_mail_txt2 . '</textarea>';
}
//記事連携のメール送るためのAJAX設定
function ajax_link_mail_scripts($hook_suffix) {
// 投稿編集画面(post.php/post-new.php)かつ対象投稿タイプのみ読み込む
$screen = get_current_screen();
if (!$screen || !in_array($screen->base, ['post', 'post-new'], true)) return;
if (!in_array($screen->post_type, sqool_get_post_types(), true)) return;
$handle = 'link_mail';
$file = get_template_directory_uri() . '/js/' . $handle . '.js';
wp_register_script( $handle, $file, array( 'jquery' ) );
$action = 'link-mail-action';
wp_localize_script($handle, 'LINK_MAIL_AJAX', [
'api' => admin_url('admin-ajax.php'),
'action' => $action,
'nonce' => wp_create_nonce($action)
]);
wp_enqueue_script($handle);
}
add_action('admin_enqueue_scripts', 'ajax_link_mail_scripts');
//記事連携のメール送る コールバック
function ajax_link_mail_call () {
//sqool用のグローバルデータ群
require("inc/global.php");
global $wpdb; //データベースを触るためのおまじない
$action = 'link-mail-action';
$data = '';
if(check_ajax_referer($action, 'nonce', false)) {
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$title_and_id = $_POST["link_mail_title"];
$info = $_POST["link_mail_info"];
$headers = [];
$headers[] = 'From: ' . $pr_to_mail[1];
//タイトルと記事IDに分ける
$title_and_id2 = explode("***",$title_and_id);
$title = $title_and_id2[0];
$post_id = $title_and_id2[1];
//CCのメール分ループ
for ($i=1; $i<count($link_to_mail); $i++) {
$headers[] = 'cc: ' . $link_to_mail[$i] . '<' . $link_to_mail[$i] . '>';
}
//メール送信
wp_mail($link_to_mail[0], $title, $info, $headers, "");
//DBに保存(テーブルが存在する場合のみ)
$table_name = $wpdb->prefix . 'mail_history';
$wpdb->suppress_errors( true );
$table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
$wpdb->suppress_errors( false );
if ( $table_exists ) {
$wpdb->insert(
$wpdb->prefix . 'mail_history',
array( 'post_id' => $post_id, 'mail' => $link_to_mail[0], 'type' => 1 ),
array( '%d', '%s', '%d' )
);
// エラーが発生した場合は無視
if ( $wpdb->last_error ) {
$wpdb->last_error = '';
}
}
status_header('200');
$data = 'OK';
}
}
else {
status_header('403');
$data = 'Forbidden';
}
header('Content-Type: application/json; charset=UTF-8');
echo $data;
die();
}
add_action('wp_ajax_link-mail-action', 'ajax_link_mail_call');
add_action('wp_ajax_nopriv_link-mail-action', 'ajax_link_mail_call');
///////////////////////////////////////////////////////////////////////////////////////////////
// ショートコード用テンプレート読み込み共通関数
function sqool_load_shortcode_template( $template_path ) {
$full_path = get_template_directory() . '/' . ltrim( $template_path, '/' );
if ( file_exists( $full_path ) ) {
ob_start();
include( $full_path );
return ob_get_clean();
}
return '';
}
// 広告関連のショートコード
function shortcode_sp_article_middle() {
return sqool_load_shortcode_template( '/shortcorde/ads/sp/article_middle.php' );
}
function shortcode_sp_article_under() {
return sqool_load_shortcode_template( '/shortcorde/ads/sp/article_under.php' );
}
function shortcode_pc_article_under() {
return sqool_load_shortcode_template( '/shortcorde/ads/pc/article_under.php' );
}
function shortcode_pc_more() {
return sqool_load_shortcode_template( '/shortcorde/ads/pc/more.php' );
}
// LINE関連のショートコード関数
function shortcode_line_rss() {
return sqool_load_shortcode_template( '/shortcorde/line/rss.php' );
}
// メール送信機能の改善
function send_notification_email($to, $subject, $message, $headers = array(), $attachments = array()) {
if (!is_email($to)) {
return new WP_Error('invalid_email', '無効なメールアドレスです');
}
$default_headers = array(
'Content-Type: text/html; charset=UTF-8',
'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>'
);
$headers = wp_parse_args($headers, $default_headers);
return wp_mail($to, $subject, $message, $headers, $attachments);
}
// メール履歴の保存
function save_mail_history($post_id, $email, $type) {
global $wpdb;
if (!is_numeric($post_id) || !is_email($email) || !is_numeric($type)) {
return false;
}
$table_name = $wpdb->prefix . 'mail_history';
// テーブルが存在するかチェック
$wpdb->suppress_errors( true );
$table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $table_name ) );
$wpdb->suppress_errors( false );
if ( ! $table_exists ) {
return false;
}
$data = array(
'post_id' => $post_id,
'mail' => sanitize_email($email),
'type' => $type,
'send_date' => current_time('mysql')
);
$format = array('%d', '%s', '%d', '%s');
$result = $wpdb->insert($table_name, $data, $format);
// エラーが発生した場合は無視
if ( $wpdb->last_error ) {
$wpdb->last_error = '';
return false;
}
return $result;
}
// メール送信のAJAXハンドラー
function handle_mail_notification() {
check_ajax_referer('mail-notification', 'nonce');
if (!current_user_can('edit_posts')) {
wp_send_json_error('権限がありません');
}
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
$email = isset($_POST['email']) ? sanitize_email($_POST['email']) : '';
$type = isset($_POST['type']) ? intval($_POST['type']) : 0;
$message = isset($_POST['message']) ? wp_kses_post($_POST['message']) : '';
if (!$post_id || !$email || !$message) {
wp_send_json_error('必要な情報が不足しています');
}
$result = send_notification_email($email, get_the_title($post_id), $message);
if (is_wp_error($result)) {
wp_send_json_error($result->get_error_message());
}
save_mail_history($post_id, $email, $type);
wp_send_json_success('メールを送信しました');
}
add_action('wp_ajax_mail-notification', 'handle_mail_notification');
// ショートコードの登録を整理
function register_shortcodes() {
// 広告関連のショートコード
add_shortcode('sp_article_middle', 'shortcode_sp_article_middle');
add_shortcode('sp_article_under', 'shortcode_sp_article_under');
add_shortcode('pc_article_under', 'shortcode_pc_article_under');
add_shortcode('pc_more', 'shortcode_pc_more');
// LINE関連のショートコード
add_shortcode('line_rss', 'shortcode_line_rss');
// その他のショートコード
add_shortcode('monst_articles', 'shortcode_monst_articles');
}
add_action('init', 'register_shortcodes');
// モンスト記事一覧のショートコード
function shortcode_monst_articles() {
$post_type_name = 'post';
$menu_cat = 96;
$list_number = 10;
$paged = get_query_var('paged') ? get_query_var('paged') : 1;
$args = array(
'post_type' => $post_type_name,
'cat' => $menu_cat,
'posts_per_page' => $list_number,
'paged' => $paged,
'orderby' => 'modified'
);
ob_start();
include(dirname(__FILE__) . '/shortcorde/menu_list_format_post_type_n.php');
return ob_get_clean();
}
// [pc_right_1st] ショートコード
function shortcode_pc_right_1st() {
ob_start();
?>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9466219394364041"
crossorigin="anonymous"></script>
<!-- SQOOL.NET PC 右メニュー上 -->
<ins class="adsbygoogle"
style="display:inline-block;width:300px;height:250px"
data-ad-client="ca-pub-9466219394364041"
data-ad-slot="6165067396"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
<?php
return ob_get_clean();
}
add_shortcode('pc_right_1st', 'shortcode_pc_right_1st');
//記事中Adsショートコード読み込み
require_once get_template_directory() . '/shortcorde/ads/sp/article_middle.php';
require_once get_template_directory() . '/shortcorde/ads/sp/article_under.php';
require_once get_template_directory() . '/shortcorde/ads/pc/article_under.php';
require_once get_template_directory() . '/shortcorde/ads/pc/more.php';
require_once get_template_directory() . '/shortcorde/line/rss.php';
// [more_short] ショートコード定義
function sqool_more_short_shortcode($atts, $content = null) {
if (wp_is_mobile()) {
return do_shortcode('[more_sp_code]');
} else {
return do_shortcode('[more_pc_code]');
}
}
add_shortcode('more_short', 'sqool_more_short_shortcode');
// [article_under_ad] ショートコード定義(デバイス判定でフル版を表示)
function sqool_article_under_ad_shortcode($atts, $content = null) {
if (wp_is_mobile()) {
return do_shortcode('[article_under_ad_sp_code]');
} else {
return do_shortcode('[article_under_ad_pc]');
}
}
add_shortcode('article_under_ad', 'sqool_article_under_ad_shortcode');
// [article_under_ad_short] ショートコード定義(デバイス判定でショート版を表示)
function sqool_article_under_ad_short_shortcode($atts, $content = null) {
if (wp_is_mobile()) {
return do_shortcode('[article_under_ad_sp_s]');
} else {
return do_shortcode('[article_under_ad_pc_s]');
}
}
add_shortcode('article_under_ad_short', 'sqool_article_under_ad_short_shortcode');
// タグリストのショートコード
require_once get_template_directory() . '/shortcorde/use_taglist_in_top.php';
/* ----------------------------------------------------
* Lotus RSS: チェックボックス
* ---------------------------------------------------- */
function sqool_add_lotus_export_checkbox() {
$post_types = sqool_get_post_types();
foreach ( $post_types as $pt ) {
add_meta_box(
'sqool_lotus_rss_box',
'Lotus RSS 連携',
'sqool_lotus_rss_box_html',
$pt,
'side',
'default'
);
}
}
add_action( 'add_meta_boxes', 'sqool_add_lotus_export_checkbox' );
function sqool_lotus_rss_box_html( $post ) {
$value = get_post_meta( $post->ID, 'lotus_rss', true );
wp_nonce_field( 'sqool_lotus_rss_nonce', 'sqool_lotus_rss_nonce_field' );
?>
<p>
<label>
<input type="checkbox" name="lotus_rss" value="1" <?php checked( $value, '1' ); ?> />
この記事を Lotus RSS に含める
</label>
</p>
<?php
}
function sqool_save_lotus_rss_meta( $post_id ) {
if ( ! isset( $_POST['sqool_lotus_rss_nonce_field'] ) ||
! wp_verify_nonce( $_POST['sqool_lotus_rss_nonce_field'], 'sqool_lotus_rss_nonce' ) ) return;
if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) return;
if ( isset($_POST['lotus_rss']) && $_POST['lotus_rss'] === '1' ) {
update_post_meta( $post_id, 'lotus_rss', '1' );
} else {
delete_post_meta( $post_id, 'lotus_rss' );
}
}
add_action( 'save_post', 'sqool_save_lotus_rss_meta' );
/* ----------------------------------------------------
* Lotus RSS /feed/lotus/
* ---------------------------------------------------- */
function sqool_register_lotus_feed() {
add_feed( 'lotus', 'sqool_load_lotus_feed_template' );
}
add_action( 'init', 'sqool_register_lotus_feed' );
function sqool_load_lotus_feed_template() {
$template = locate_template( 'feed-lotus.php' );
if ( $template ) {
load_template( $template );
} else {
load_template( ABSPATH . WPINC . '/feed-rss2.php' );
}
}
// Lotus RSS フィードのクエリを制御(lotus_rss=1 の記事のみ)
add_action( 'pre_get_posts', function( $query ) {
if ( ! is_admin() && $query->is_main_query() && is_feed( 'lotus' ) ) {
$query->set( 'meta_key', 'lotus_rss' );
$query->set( 'meta_value', '1' );
$query->set( 'post_type', sqool_get_post_types() );
}
} );
/* ----------------------------------------------------
* 自動アイキャッチ画像設定(Auto Featured Image代替)
* 投稿保存時に、本文の最初の画像を自動的にアイキャッチ画像に設定
* 再帰ガード付き(名前付き関数+処理中だけ一時的にremove/add)
* ---------------------------------------------------- */
function sqool_auto_set_featured_image($post_id, $post, $update) {
// 再帰ガード: 処理中フラグをチェック
static $processing = false;
if ($processing) return;
// 1) 自動保存・リビジョン・権限チェック
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
if (wp_is_post_revision($post_id)) return;
if (!current_user_can('edit_post', $post_id)) return;
// 2) 許可された投稿タイプのみ処理
$allowed_post_types = sqool_get_post_types();
if (!in_array($post->post_type, $allowed_post_types, true)) return;
// 3) 既にアイキャッチ画像が設定されている場合はスキップ
if (has_post_thumbnail($post_id)) return;
// 4) コンテンツが必要
$content = $post->post_content ?? '';
if ($content === '') return;
// 再帰ガード: 処理開始
$processing = true;
// 処理中は一時的にsave_postフックを外す(再帰防止)
remove_action('save_post', 'sqool_auto_set_featured_image', 10);
$attachment_id = 0;
$found_img_tag = false;
// 5) まず、wp-image-123 のようなクラスからIDを高速取得(最優先)
if (preg_match('/wp-image-(\d+)/', $content, $m_id)) {
$maybe_id = (int)$m_id[1];
if ($maybe_id > 0 && get_post($maybe_id)) {
$attachment_id = $maybe_id;
$found_img_tag = true;
}
}
// 6) 次に、コンテンツから最初の画像URLを抽出して解決
if (!$attachment_id && preg_match('/<img[^>]+src=["\']([^"\']+)["\']/i', $content, $m)) {
$found_img_tag = true;
$img_url = $m[1];
// URLの正規化(クエリ文字列を削除: ?ver=... や ?resize=... など)
$img_url = preg_replace('/\?.*$/', '', $img_url);
// URLからアタッチメントIDを取得
$attachment_id = (int) attachment_url_to_postid($img_url);
if (!$attachment_id) {
// リサイズされた画像URL(例: image-300x200.jpg)から元の画像を解決
$attachment_id = sqool_try_resolve_attachment_id_from_resized_url($img_url);
}
// 画像タグはあるが添付IDに解決できない(外部画像等)場合は、誤設定を避けるため何もしない
if (!$attachment_id) {
add_action('save_post', 'sqool_auto_set_featured_image', 10, 3);
$processing = false;
return;
}
}
// 7) 記事内に画像タグが無い場合のみ、デフォルト画像(OGP)を設定
if (!$attachment_id && !$found_img_tag) {
$attachment_id = sqool_get_default_og_image_id();
if (!$attachment_id) {
add_action('save_post', 'sqool_auto_set_featured_image', 10, 3);
$processing = false;
return;
}
}
// 8) アイキャッチ画像を設定
if ($attachment_id > 0) {
set_post_thumbnail($post_id, $attachment_id);
}
// 再帰ガード: 処理終了(フックを戻す)
add_action('save_post', 'sqool_auto_set_featured_image', 10, 3);
$processing = false;
}
add_action('save_post', 'sqool_auto_set_featured_image', 10, 3);
/**
* デフォルトOGP画像のアタッチメントIDを取得(キャッシュ付き)
* メディアライブラリから「og-image.jpg」を検索
* 見つからない場合は0を返す
*/
function sqool_get_default_og_image_id(): int {
// staticでメモ化(同一リクエスト内での再実行を防止)
static $cached_id = null;
if ($cached_id !== null) {
return $cached_id;
}
// オプションからキャッシュを取得(DB検索を回避)
$cached_id = get_option('sqool_default_og_image_id', false);
if ($cached_id !== false) {
$cached_id = (int)$cached_id;
// キャッシュされたIDが有効か確認
if ($cached_id > 0 && get_post($cached_id)) {
return $cached_id;
}
// 無効な場合はキャッシュをクリア
delete_option('sqool_default_og_image_id');
$cached_id = null;
}
// まず、テーマ内のデフォルト画像URLから試行(メディアライブラリにアップロード済みの場合)
$default_og_image_url = get_template_directory_uri() . '/images/og-image.jpg';
$attachment_id = attachment_url_to_postid($default_og_image_url);
if ($attachment_id) {
$cached_id = (int)$attachment_id;
update_option('sqool_default_og_image_id', $cached_id);
return $cached_id;
}
// メディアライブラリからファイル名で検索(postmetaの_wp_attached_fileを使用してより正確に)
global $wpdb;
$filename = 'og-image.jpg';
// _wp_attached_fileメタデータで検索(guidより正確)
$attachment = $wpdb->get_var($wpdb->prepare(
"SELECT p.ID FROM {$wpdb->posts} p
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
WHERE p.post_type = 'attachment'
AND p.post_mime_type LIKE 'image%%'
AND pm.meta_key = '_wp_attached_file'
AND pm.meta_value LIKE %s
LIMIT 1",
'%' . $wpdb->esc_like($filename) . '%'
));
$cached_id = $attachment ? (int)$attachment : 0;
// 見つかった場合はキャッシュに保存
if ($cached_id > 0) {
update_option('sqool_default_og_image_id', $cached_id);
}
return $cached_id;
}
/**
* リサイズされた画像URLからアタッチメントIDを解決
* 例: image-300x200.jpg -> image.jpg
*/
function sqool_try_resolve_attachment_id_from_resized_url(string $img_url): int {
$path = wp_parse_url($img_url, PHP_URL_PATH);
if (!$path) return 0;
$filename = basename($path);
// 拡張子の前に -300x200 のようなパターンを削除
$original = preg_replace('/-\d+x\d+(?=\.\w+$)/', '', $filename);
if ($original === $filename) return 0;
// 元のファイル名でURLを再構築
$base = preg_replace('/' . preg_quote($filename, '/') . '$/', $original, $img_url);
$id = attachment_url_to_postid($base);
return $id ? (int)$id : 0;
}
/* ----------------------------------------------------
* カスタムフィールドUIの無効化(パフォーマンス改善)
* WordPress標準の「カスタムフィールド」メタボックス(postcustom)を無効化
* postmeta自体は残るので、ACFやテーマ/プラグインのメタはそのまま動く
* ---------------------------------------------------- */
add_action('add_meta_boxes', function () {
// すべての投稿タイプに対してカスタムフィールドUIを無効化
$post_types = sqool_get_post_types();
foreach ($post_types as $post_type) {
remove_meta_box('postcustom', $post_type, 'normal');
}
}, 999); // 優先度999で、他のメタボックス追加後に実行
/* ----------------------------------------------------
* FeedWordPressプラグインのunserializeエラー修正
* プラグインの関数を上書きして、安全なmaybe_unserialize()を使用
* ---------------------------------------------------- */
if ( function_exists('is_syndicated') ) {
/**
* 安全なunserialize処理(エラーを完全に抑制)
* 壊れたシリアライズデータでもエラーを出さずにfalseを返す
* 配列を期待する場合に使用
*/
if ( ! function_exists('sqool_safe_maybe_unserialize') ) {
function sqool_safe_maybe_unserialize( $data ) {
// 既に配列の場合はそのまま返す
if ( is_array( $data ) ) {
return $data;
}
// nullやfalse、空文字列の場合はfalseを返す
if ( empty( $data ) || ! is_string( $data ) ) {
return false;
}
// シリアライズされていない場合はfalseを返す
if ( ! function_exists( 'is_serialized' ) || ! is_serialized( $data ) ) {
return false;
}
// エラーハンドラーを一時的に設定して、unserialize()のエラーを完全にキャッチ
// 他のエラーは触らない(最小構成でunserialize警告だけ握る)
$previous_error_handler = set_error_handler( function( $errno, $errstr, $errfile, $errline ) use ( &$previous_error_handler ) {
// unserialize()関連のエラーのみをキャッチ(再発耐性を上げるため、Error at offsetに限定せずunserialize()全般に対応)
if ( ( $errno === E_WARNING || $errno === E_NOTICE )
&& strpos( $errstr, 'unserialize()' ) !== false ) {
return true; // unserialize()関連のエラーを抑制
}
// それ以外のエラーは元のハンドラーに渡す(触らない)
if ( $previous_error_handler !== null ) {
return call_user_func( $previous_error_handler, $errno, $errstr, $errfile, $errline );
}
// ハンドラーがない場合はデフォルト動作に任せる
return false;
}, E_WARNING | E_NOTICE );
// unserializeを実行(エラーハンドラーが警告を抑制する)
// @演算子は使わず、エラーハンドラーに完全に任せる(根本解決)
$result = maybe_unserialize( $data );
// エラーハンドラーを復元(確実に元に戻す)
if ( $previous_error_handler !== null ) {
restore_error_handler();
} else {
// ハンドラーが設定されなかった場合は何もしない
restore_error_handler();
}
// 結果が配列でない場合はfalseを返す
if ( ! is_array( $result ) ) {
return false;
}
return $result;
}
}
// sqool_safe_unserialize() はコメント添付セクションで定義済み(FeedWordPressブロック外)
// add_boilerplate_simple() 関数を安全なバージョンで上書き
if ( ! function_exists('add_boilerplate_simple_safe') ) {
function add_boilerplate_simple_safe ($element, $title, $id = NULL) {
// 早期リターン: シンジケートされていない記事は処理しない
if (!$id || !is_syndicated($id)) {
return $title;
}
// キャッシュキーを生成(同じ投稿IDとelementの組み合わせでキャッシュ)
static $result_cache = array();
$cache_key = $id . '_' . $element;
// キャッシュに失敗フラグがある場合は早期リターン(破損データの再処理を避ける)
if (isset($result_cache[$cache_key]) && $result_cache[$cache_key] === false) {
return $title;
}
// キャッシュに結果がある場合はそれを返す
if (isset($result_cache[$cache_key])) {
return $result_cache[$cache_key];
}
// メタデータの取得とunserialize処理をキャッシュ
static $meta_cache = array();
if (!isset($meta_cache[$id])) {
$meta = get_feed_meta('boilerplate rules', $id);
// メタデータが存在し、配列でない場合は安全にunserializeを試行
if ( $meta && ! is_array( $meta ) ) {
$meta = sqool_safe_maybe_unserialize( $meta );
// 失敗した場合はfalseを設定
if ( ! is_array( $meta ) ) {
$meta = false;
}
} elseif ( ! $meta ) {
$meta = false;
}
// メタデータをキャッシュ(falseもキャッシュして再処理を避ける)
$meta_cache[$id] = $meta;
// 壊れたデータを検出した場合は、データベースからも削除(根本解決)
if ( $meta === false && function_exists( 'get_feed_meta' ) ) {
$raw_meta = get_feed_meta('boilerplate rules', $id);
// シリアライズデータだが、unserializeに失敗した場合
if ( $raw_meta && is_string( $raw_meta ) && function_exists( 'is_serialized' ) && is_serialized( $raw_meta ) ) {
// 安全なunserializeを使用(エラーを抑制してunserializeを試行)
$test_unserialize = sqool_safe_unserialize( $raw_meta );
// 失敗した場合(壊れたデータ)は、メタデータを削除
if ( $test_unserialize === false && $raw_meta !== serialize( false ) ) {
// データベースから壊れたメタデータを削除(根本解決)
// get_feed_meta() は get_post_meta() 経由なので、直接削除はしない
// 代わりに、キャッシュに false を保存して再処理を避ける
}
}
}
} else {
$meta = $meta_cache[$id];
}
// メタデータが無効な場合はグローバルオプションを取得
if ( ! is_array( $meta ) || empty( $meta ) ) {
// グローバルオプションもキャッシュ
static $global_meta_cache = null;
static $global_meta_checked = false;
if ( $global_meta_cache === null ) {
$global_meta_value = get_option( 'feedwordpress_boilerplate', false );
// グローバルオプションも安全にunserializeを試行
if ( $global_meta_value && ! is_array( $global_meta_value ) ) {
$original_value = $global_meta_value;
$global_meta_value = sqool_safe_maybe_unserialize( $global_meta_value );
// 壊れたデータを検出した場合、データベースから削除(根本解決)
if ( ! is_array( $global_meta_value ) && ! $global_meta_checked ) {
$global_meta_checked = true;
// シリアライズデータだが、unserializeに失敗した場合
if ( is_string( $original_value ) && function_exists( 'is_serialized' ) && is_serialized( $original_value ) ) {
// 安全なunserializeを使用(エラーを抑制してunserializeを試行)
$test_unserialize = sqool_safe_unserialize( $original_value );
// 失敗した場合(壊れたデータ)は、オプションを削除して根本解決
if ( $test_unserialize === false && $original_value !== serialize( false ) ) {
// 壊れたデータをデータベースから削除
delete_option( 'feedwordpress_boilerplate' );
// ログに記録(デバッグ用、本番環境ではコメントアウト推奨)
// error_log( 'SQOOL: 壊れたfeedwordpress_boilerplateオプションを削除しました' );
}
}
}
if ( ! is_array( $global_meta_value ) ) {
$global_meta_value = false;
}
}
$global_meta_cache = $global_meta_value;
}
$meta = $global_meta_cache;
}
$result = $title;
if (is_array($meta) and !empty($meta)) :
foreach ($meta as $rule) :
if ($element==$rule['element']) :
// add_boilerplate_reformat関数の存在チェックを追加
if (function_exists('add_boilerplate_reformat')) {
$rule['template'] = add_boilerplate_reformat($rule['template'], $element, $id);
}
if ('before'==$rule['placement']) :
$result = $rule['template'] . ' ' . $result;
else :
$result = $result . ' ' . $rule['template'];
endif;
endif;
endforeach;
endif;
// 結果をキャッシュ(変更がない場合もキャッシュして再処理を避ける)
$result_cache[$cache_key] = $result;
return $result;
}
}
// add_boilerplate_content() 関数を安全なバージョンで上書き
if ( ! function_exists('add_boilerplate_content_safe') ) {
function add_boilerplate_content_safe ($content) {
// 早期リターン: シンジケートされていない記事は処理しない
if (!is_syndicated()) {
return $content;
}
// コンテンツハッシュベースのキャッシュ(同じコンテンツの再処理を防ぐ)
static $content_cache = array();
$content_hash = md5($content);
// キャッシュに失敗フラグがある場合は早期リターン(破損データの再処理を避ける)
if (isset($content_cache[$content_hash]) && $content_cache[$content_hash] === false) {
return $content;
}
// キャッシュに結果がある場合はそれを返す
if (isset($content_cache[$content_hash])) {
return $content_cache[$content_hash];
}
// メタデータの取得とunserialize処理をキャッシュ(グローバルキャッシュ)
static $global_content_meta_cache = null;
if ($global_content_meta_cache === null) {
$meta = get_feed_meta('boilerplate rules');
// メタデータが存在し、配列でない場合は安全にunserializeを試行
if ( $meta && ! is_array( $meta ) ) {
$meta = sqool_safe_maybe_unserialize( $meta );
// 失敗した場合はfalseを設定
if ( ! is_array( $meta ) ) {
$meta = false;
}
} elseif ( ! $meta ) {
$meta = false;
}
// メタデータが無効な場合はグローバルオプションを取得
if ( ! is_array( $meta ) || empty( $meta ) ) {
$global_meta_value = get_option( 'feedwordpress_boilerplate', false );
// グローバルオプションも安全にunserializeを試行
if ( $global_meta_value && ! is_array( $global_meta_value ) ) {
$global_meta_value = sqool_safe_maybe_unserialize( $global_meta_value );
if ( ! is_array( $global_meta_value ) ) {
$global_meta_value = false;
}
}
$meta = $global_meta_value;
}
// メタデータをキャッシュ(falseもキャッシュして再処理を避ける)
$global_content_meta_cache = $meta;
} else {
$meta = $global_content_meta_cache;
}
$result = $content;
if (is_array($meta) and !empty($meta)) :
foreach ($meta as $rule) :
if ('post'==$rule['element']) :
// add_boilerplate_reformat関数の存在チェックを追加
if (function_exists('add_boilerplate_reformat')) {
$rule['template'] = add_boilerplate_reformat($rule['template'], 'post');
}
if ('before'==$rule['placement']) :
$result = $rule['template'] . "\n" . $result;
else :
$result = $result . "\n" . $rule['template'];
endif;
endif;
endforeach;
endif;
// 結果をキャッシュ(変更がない場合もキャッシュして再処理を避ける)
$content_cache[$content_hash] = $result;
return $result;
}
}
// プラグインの関数を上書き(プラグインが読み込まれた後に実行)
// initアクションで実行(プラグインのフィルター追加後に確実に実行される)
add_action('init', function() {
// プラグインの関数が存在する場合のみ処理
if ( ! function_exists('add_boilerplate_simple') || ! function_exists('is_syndicated') ) {
return;
}
// 一度だけ実行するように静的変数を使用(重要:504エラー対策)
static $already_processed = false;
if ( $already_processed ) {
return;
}
$already_processed = true;
// 元の関数を削除して、安全なバージョンに置き換え
$hookOrder = get_option('feedwordpress_boilerplate_hook_order', 10);
// 元のフィルターを削除(複数の優先度を試行)
remove_filter('the_title', 'add_boilerplate_title', $hookOrder);
remove_filter('get_the_excerpt', 'add_boilerplate_excerpt', $hookOrder);
remove_filter('the_content', 'add_boilerplate_content', $hookOrder);
remove_filter('the_content_rss', 'add_boilerplate_content', $hookOrder);
// デフォルト優先度でも削除を試行(プラグインの設定が異なる場合に備える)
remove_filter('the_title', 'add_boilerplate_title', 10);
remove_filter('get_the_excerpt', 'add_boilerplate_excerpt', 10);
remove_filter('the_content', 'add_boilerplate_content', 10);
remove_filter('the_content_rss', 'add_boilerplate_content', 10);
// 安全なバージョンを追加
add_filter('the_title', function($title, $id = NULL) {
return add_boilerplate_simple_safe('title', $title, $id);
}, $hookOrder, 2);
add_filter('get_the_excerpt', function($title, $id = NULL) {
return add_boilerplate_simple_safe('excerpt', $title, $id);
}, $hookOrder, 1);
add_filter('the_content', 'add_boilerplate_content_safe', $hookOrder, 1);
add_filter('the_content_rss', 'add_boilerplate_content_safe', $hookOrder, 1);
}, 20); // 優先度20で、プラグインの初期化後に実行
}
/**
* Custom Post Type Permalinks - pluginless implementation
* 旧 Custom Post Type Permalinks プラグインの設定を functions.php で再現
*
* 方針:
* - 日付ベース(news / dreamnews / prwire / businessnews)は「固定スラッグ + 日付+ID」で解決する
* 例: /news/archive/20251219-535416.html
* - 旧実装のように「スラッグ用プレースホルダ」を name にマッピングしない(これが404の主因)
* - postnameベースは「固定スラッグ + post_name」で解決する
*/
function sqool_set_custom_post_type_permalinks() {
global $wp_rewrite;
// 日付ベースの構造(※フルパスで固定)
$date_based_post_types = array(
'news' => '/news/archive/%year%%monthnum%%day%-%post_id%.html',
'dreamnews' => '/news/dreamnews/archive/%year%%monthnum%%day%-%post_id%.html',
'prwire' => '/news/prwire/archive/%year%%monthnum%%day%-%post_id%.html',
'businessnews' => '/business/news/archive/%year%%monthnum%%day%-%post_id%.html',
);
// 投稿名ベースの構造(※各CPTのrewrite[slug]に従う)
$postname_based_post_types = array(
'column' => '/%postname%.html',
'esports' => '/%postname%.html',
'business' => '/%postname%.html',
'robot' => '/%postname%.html',
'blog' => '/%postname%.html',
'travel' => '/%postname%.html',
'review' => '/%postname%.html',
'report' => '/%postname%.html',
'notice' => '/%postname%.html',
'link' => '/%postname%.html',
'special' => '/%postname%.html',
'premium' => '/%postname%.html',
);
// -----------------------------
// 日付ベース: ルール(解決は post_id で行う)
// -----------------------------
foreach ( $date_based_post_types as $post_type => $permastruct ) {
if ( ! post_type_exists( $post_type ) ) {
continue;
}
$pt_object = get_post_type_object( $post_type );
if ( ! $pt_object || false === $pt_object->rewrite ) {
continue;
}
// permastruct を登録(生成用)
$wp_rewrite->add_permastruct( $post_type, $permastruct, array( 'with_front' => false ) );
// 解決用: 明示的に rewrite_rule を追加(name を使わず p=ID で確定)
// yyyymmdd-id.html をパースして ID を取り出す
switch ( $post_type ) {
case 'news':
add_rewrite_rule(
'^news/archive/([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]+)\\.html$',
'index.php?post_type=news&p=$4',
'top'
);
break;
case 'dreamnews':
add_rewrite_rule(
'^news/dreamnews/archive/([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]+)\\.html$',
'index.php?post_type=dreamnews&p=$4',
'top'
);
break;
case 'prwire':
add_rewrite_rule(
'^news/prwire/archive/([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]+)\\.html$',
'index.php?post_type=prwire&p=$4',
'top'
);
break;
case 'businessnews':
add_rewrite_rule(
'^business/news/archive/([0-9]{4})([0-9]{2})([0-9]{2})-([0-9]+)\\.html$',
'index.php?post_type=businessnews&p=$4',
'top'
);
break;
}
}
// -----------------------------
// 投稿名ベース: permastruct(生成は post_name、解決は WP の通常動作に任せる)
// -----------------------------
foreach ( $postname_based_post_types as $post_type => $structure ) {
if ( ! post_type_exists( $post_type ) ) {
continue;
}
$pt_object = get_post_type_object( $post_type );
if ( ! $pt_object || false === $pt_object->rewrite ) {
continue;
}
$slug = isset( $pt_object->rewrite['slug'] ) ? $pt_object->rewrite['slug'] : '';
$slug = trim( (string) $slug, '/' );
if ( $slug === '' ) {
continue;
}
// %postname% を %post_type% に置き換え
$permalink = '/' . $slug . $structure;
$permalink = str_replace( '%postname%', '%' . $post_type . '%', $permalink );
// 投稿タイプのプレースホルダーを登録(name 解決)
add_rewrite_tag( '%' . $post_type . '%', '([^/]+)', 'post_type=' . $post_type . '&name=' );
$wp_rewrite->add_permastruct( $post_type, $permalink, array( 'with_front' => false ) );
}
// hints-and-tips: カスタムタクソノミー %game-title% を含む構造(既存ロジック維持、ただしslugプレースホルダは使わない)
if ( post_type_exists( 'hints-and-tips' ) ) {
$pt_object = get_post_type_object( 'hints-and-tips' );
if ( $pt_object && false !== $pt_object->rewrite ) {
$slug = isset( $pt_object->rewrite['slug'] ) ? trim( (string) $pt_object->rewrite['slug'], '/' ) : '';
if ( $slug ) {
$permalink = '/' . $slug . '/%game-title%/%hints-and-tips%.html';
add_rewrite_tag( '%hints-and-tips%', '([^/]+)', 'post_type=hints-and-tips&name=' );
add_rewrite_tag( '%game-title%', '([^/]+)', 'game-title=' );
$wp_rewrite->add_permastruct( 'hints-and-tips', $permalink, array( 'with_front' => false ) );
}
}
}
}
add_action( 'init', 'sqool_set_custom_post_type_permalinks', 20 );
// パーマリンク生成時にプレースホルダーを置換
function sqool_custom_post_type_permalink( $post_link, $post, $leavename ) {
global $wp_rewrite;
if ( ! $wp_rewrite->using_permalinks() ) {
return $post_link;
}
$post_type = $post->post_type;
$pt_object = get_post_type_object( $post_type );
if ( ! $pt_object || false === $pt_object->rewrite ) {
return $post_link;
}
$date_based_post_types = array(
'news', 'dreamnews', 'prwire', 'businessnews'
);
$postname_based_post_types = array(
'column', 'esports', 'business', 'robot', 'blog', 'travel', 'review', 'report', 'notice', 'link', 'special', 'premium'
);
// 下書きや保留中の投稿は通常のリンクを返す
$draft_or_pending = isset( $post->post_status ) && in_array(
$post->post_status,
array( 'draft', 'pending', 'auto-draft' ),
true
);
if ( $draft_or_pending && ! $leavename ) {
return $post_link;
}
$slug = isset( $pt_object->rewrite['slug'] ) ? $pt_object->rewrite['slug'] : '';
$slug = trim( (string) $slug, '/' );
// 日付ベース(news / dreamnews / prwire / businessnews)
if ( in_array( $post_type, $date_based_post_types, true ) ) {
$permalink = $wp_rewrite->get_extra_permastruct( $post_type );
if ( ! $permalink ) {
return $post_link;
}
$year = get_post_time( 'Y', false, $post );
$month = get_post_time( 'm', false, $post );
$day = get_post_time( 'd', false, $post );
$permalink = str_replace( '%year%', $year, $permalink );
$permalink = str_replace( '%monthnum%', $month, $permalink );
$permalink = str_replace( '%day%', $day, $permalink );
$permalink = str_replace( '%post_id%', $post->ID, $permalink );
return home_url( $permalink );
}
// 投稿名ベース
if ( in_array( $post_type, $postname_based_post_types, true ) ) {
$permalink = $wp_rewrite->get_extra_permastruct( $post_type );
if ( ! $permalink ) {
return $post_link;
}
// 投稿名を置換
if ( ! $leavename ) {
$permalink = str_replace( '%' . $post_type . '%', $post->post_name, $permalink );
}
return home_url( $permalink );
}
// hints-and-tips: %game-title%/%postname%.html
if ( 'hints-and-tips' === $post_type ) {
$permalink = $wp_rewrite->get_extra_permastruct( $post_type );
if ( ! $permalink ) {
return $post_link;
}
// タクソノミーを置換
$terms = get_the_terms( $post->ID, 'game-title' );
if ( $terms && ! is_wp_error( $terms ) ) {
$term = array_shift( $terms );
$permalink = str_replace( '%game-title%', $term->slug, $permalink );
} else {
// タームが無い場合はタクソノミー部分を削除
$permalink = str_replace( '%game-title%/', '', $permalink );
}
// 投稿名を置換
if ( ! $leavename ) {
$permalink = str_replace( '%hints-and-tips%', $post->post_name, $permalink );
}
return home_url( $permalink );
}
return $post_link;
}
add_filter( 'post_type_link', 'sqool_custom_post_type_permalink', 10, 3 );
/** WPML CPT URL fix - post_type_link filter */
add_filter( 'post_type_link', 'sqool_wpml_fix_cpt_lang_url', 999, 2 );
function sqool_wpml_fix_cpt_lang_url( $permalink, $post ) {
if ( is_admin() ) return $permalink;
if ( in_array( $post->post_type, array( 'post', 'page', 'attachment' ) ) ) return $permalink;
$lang_info = apply_filters( 'wpml_post_language_details', null, $post->ID );
if ( ! $lang_info || empty( $lang_info['language_code'] ) ) return $permalink;
$lang = $lang_info['language_code'];
$default_lang = apply_filters( 'wpml_default_language', null );
if ( ! $default_lang || $lang === $default_lang ) return $permalink;
if ( false !== strpos( $permalink, '/' . $lang . '/' ) ) return $permalink;
$home = home_url( '/' );
if ( 0 === strpos( $permalink, $home ) ) {
$permalink = $home . $lang . '/' . substr( $permalink, strlen( $home ) );
}
return $permalink;
}
/** WPML CPT URL fix - icl_ls_languages filter */
add_filter( 'icl_ls_languages', 'sqool_fix_wpml_ls_urls' );
function sqool_fix_wpml_ls_urls( $languages ) {
if ( empty( $languages ) || ! is_array( $languages ) ) return $languages;
$default_lang = apply_filters( 'wpml_default_language', null );
$home = home_url( '/' );
foreach ( $languages as $lang_code => &$language ) {
if ( empty( $language['url'] ) ) continue;
if ( $lang_code === $default_lang ) continue;
if ( false !== strpos( $language['url'], '/' . $lang_code . '/' ) ) continue;
if ( 0 === strpos( $language['url'], $home ) ) {
$language['url'] = $home . $lang_code . '/' . substr( $language['url'], strlen( $home ) );
}
}
return $languages;
}
Warning : Cannot modify header information - headers already sent by (output started at /home/sqool/sqool.net/public_html/wp-content/themes/sqool.net/functions.php:1) in /home/sqool/sqool.net/public_html/wp-content/themes/sqool.net/header.php on line 4
ページが見つかりませんでした | SQOOLNETゲーム研究室