[WordPress]CSSとJSファイルを更新したらすぐに反映させるようにする

CSSファイルやJSファイルの中身を書き換えても、クライアントでキャッシュされていて、すぐに反映されないことになります。

スーパーリドード(ChoromeだとCtrl+F5)でキャシュは解消されて変更が反映されますが、すでに運用中などサイト閲覧者にもすぐに反映されるようにしたい場合はどうすればいいか、という話。

通常、スタイルシートの指定は、

<link rel='stylesheet' id='style-css' href='http://hoge.jp/wp-content/themes/sample/style.css' type='text/css' media='all' />

のようにしますが、ファイル名の指定のところで、?var=20171116のようにクエリを追加することで、別ファイル扱いとなり、キャシュされ直される、みたいなことのようです。

<link rel='stylesheet' id='style-css' href='http://hoge.jp/wp-content/themes/sample/style.css?ver=20171116' type='text/css' media='all' />

ということでCSSファイル名にバージョンをクエリで追加することになるのですが、いちいちバージョン名を書き換えるのは面倒なので、ファイルの更新日をfilemtime()関数で取得して追加することにしました。

こんな感じで。

function my_scripts(){
	//style.cssのファイル更新日を取得
	$date =  date("Ymd" , filemtime(get_stylesheet_directory() . '/style.css'));
	//style.cssを「?ver=日付」つきで出力
	wp_enqueue_style( 'style', get_stylesheet_directory_uri().'/style.css',false,$date);
	//responsive.jsのファイル更新日を取得
	$date =  date("Ymd" , filemtime(get_stylesheet_directory() . '/responsive.js'));
	//responsive.jsを「?ver=日付」つきで出力
	wp_enqueue_script( 'responsive-jquery', get_stylesheet_directory_uri() . '/responsive.js', array(), $date, true );
}
add_action( 'wp_enqueue_scripts', 'my_scripts', 10 );
0

Auto Post Thumbnail でjpeg画像が対応しない

どうも、Auto Post Thumbnail が機能しない。

あれこれ試していた結果、どうもJPEGを認知しないらしい。
この問題はすでに気がついている方がたくさんいて、主に2つ解決策があります。

対策1 古いバージョンに戻す

2017/11現在、最新バージョンは3.4.1ですが、その一つ前3.3.3では、JPEG問題は発生しません。そこで、3.3.3にもどして使う、という解決策。

古いバージョンは、https://ja.wordpress.org/plugins/auto-post-thumbnail/advanced/ にあって、「以前のバージョン」のところからダウンロードできます。ダウンロードしたファイルを、「プラグイン」→「新規追加」→[プラグインのアップロード] で追加します。

Auto Post Thumbnail バージョン 3.4.1だと自動アイキャッチ投稿が出来ない

WPプラグイン Auto Post Thumbnail が機能しなくなったぞい!

 

対策2 function.php にコードを追記する

で、なにが問題なのか調べてみると、

最新の3.4.1では、auto-post-thumbnail.php に、次のような箇所が追加されています。

//Fix for checking file extensions
$exts = explode(".",$filename);
if(count($exts)>2)return null;
$allowed=get_allowed_mime_types();
$ext=pathinfo($new_file,PATHINFO_EXTENSION);
if(!array_key_exists($ext,$allowed))return null;

どうやら、拡張子を使って、WordPressで対応している画像かどうかをチェックしているようです。対応していない画像を投稿すると問題が起きるのでしょう。(試してないのでわかりませんが)

記述されている、get_allowed_mime_types() ですが、この関数で取得できるのは、利用できる画像タイプの配列なのです。print_r(get_allowed_mime_types()); などとして配列の中身をみてみると、 JPEGに関しては、[jpg|jpeg|jpe] => image/jpeg  となってます。

Auto Post Thumbnail の3.4.1では、jpg|jpeg|jpe と、拡張子である jpeg などが一致しているかどうかをarray_key_exists を使って調べていますが、jpg と jpg|jpeg|jpe では文字として完全一致しないので、ここで return null となって、止まってしまいます。

一方で、JPEG以外の、たとえばPNGとかGIFとかなら、array_key_exists で取得した配列が、[gif] => image/gif  、[png] => image/png なので、Auto Post Thumbnail 3.4.1 でも問題なくサムネイル画像に設定できるはずです。

この問題について、こちらで解決策が紹介されています。

https://loumo.jp/wp/archive/20170703060006/

以下をfunction.phpに追記します。

function split_combined_mimes_for_apt( $mime_types ) {
    foreach ( $mime_types as $regex => $mime_type ) {
        if ( false !== strpos( $regex, '|' ) ) {
            $keys = explode( '|', $regex );
            foreach ( $keys as $key ) {
                $mime_types[ $key ] = $mime_type;
            }
        }
    }
    return $mime_types;
}
add_filter( 'mime_types', 'split_combined_mimes_for_apt' );

get_allowed_mime_types関数に、フィルターフックを使って、[jpg] => image/jpeg 、[jpeg] => image/jpeg 、[jpe] => image/jpeg の3つを追加するようにしています。これで、Auto Post Thumbnail でも、jpegに対応できるようにしています。

対策3 Auto Post Thumbnail を改修する

もしくは、Auto Post Thumbnail3.4.1 を直接書き換えます。

    //Fix for checking file extensions
    $exts = explode(".",$filename);
    if(count($exts)>2)return null;
    $allowed=get_allowed_mime_types();
    $ext=pathinfo($new_file,PATHINFO_EXTENSION);
    //if(!array_key_exists($ext,$allowed))return null;
    if ( !preg_grep("?".$ext."?",array_keys($allowed)) ) return null;

if(!array_key_exists($ext,$allowed))return null; を消して(コメントアウト)、if ( !preg_grep("?".$ext."?",array_keys($allowed)) ) return null; を追加します。

これで、JPEGにも対応出来るはずです。

まとめ

  1. 古いバージョン3.3.3に戻す(ただし、対応しない画像タイプで問題が起きる可能性あり)
  2. フックで対応。function.phpにコードを追記する。(get_allowed_mime_types を使っている他のプラグイン等に影響を与えるかも?)
  3. Auto Post Thubmnail 3.4.1  のコードを書き換えて改修する。(今後プラグインがアップグレードされると消えてしまう)

 

0

[WordPress]海外からの不正アタックを止めるIP制限

WordPressの乗っ取り。くらうと復帰が大変です。

ということで、やっぱり防御が一番大切。
アカウントとパスワードはしっかり管理することは当然ですが、セキュリティ対策として出来ることはするべきです。

WordPressのセキュリティプラグインはSiteGuardさんがおすすめ。

SiteGuard WP Plugin

なにがいいって、開発元が日本国内で設定画面を含め、日本語であるところ。そして、ログイン画面にひらがなの文字承認がつけられるのもいいですね。

そして、SiteGuardには、ログイン履歴を見ることも出来るのですが、ある日こんなことになっていました。

DDoSアタックだか、ブルートフォースアタックだか知りませんが、数分おきにアタックされてます。やめてくれ!って感じです。

セキュリティプラグインのお陰で、ブロックもしてくれるようですが、それでも心配だしサーバーにムダな負担をかけているようで気になります。

ということで、これらの変なアクセスをブロックしてしまいます。IPアドレスの場所を見ると、ほぼ海外からのアタックですので、国内以外のIPからは管理画面のログイン画面を含め、XMLRPCなどアタックの対象になるものをブロックします。

ブロックするのは、wp-admin、wp-login.php、xmlrpc.php、wp-cron.php の4つ。
WordPressの設置ディレクトリにある、.htaccessの最後に以下を追記します。(最後に追記するのは、あまりにも行数が多いから。)

<FilesMatch "wp-admin|wp-login\.php|xmlrpc\.php|wp-cron\.php">
order deny,allow
deny from all
allow from 1.0.16.0/20
allow from 1.0.64.0/18
allow from 1.1.64.0/18
     ・
     ・
     ・
allow from 223.223.164.0/22
allow from 223.223.208.0/21
allow from 223.223.224.0/19
</FilesMatch>

allow from のところに、アクセスを許可するIPアドレスを入れておきます。が。国内のIPアドレスすべてを入れるので、かなりの行数になります。

国内のIPアドレスは、こちら→http://www.cgis.biz/tools/access/
で教えていただけます。

 

 

0

Ktai Entry で投稿した画像をサムネイルに設定する

※以下の内容は結局関係ありませんでした。

こちらに解決策を書きました。→ Auto Post Thumbnail でjpeg画像が対応しない

 

 

携帯電話(ガラケー)でも利用できる、メール投稿を所望されることが未だにあって、「Ktai entry」と「Auto Post thumbnail」の組み合わせが便利なわけです。

以前は問題なかったよう思うのだけれど、サムネイルに画像が設定されない事例があって、調べてみることに。

原因は2つ合って、一つは、Auto Post thumbnailでは、投稿された本文の中に通常設定される画像のimgタグのclassに「wp-image-xxx」が設定されているひつようがあって、このxxxを利用してサムネイルにする画像をメディアIDとして取得しているのですが、「Ktai Entry」では「wp-image-xxx」を添加してくれません。

もう一つは、「Ktai Entry」では、メールを受信して投稿する際に、publish_phoneという命令を使っているのですが、「Auto Post thumbnail」は、publish_phone をフックしていません。

なぜ、以前は問題なかったのに、今はだめなのかはわかりませんが、WordPressのアップデートに関連して、「Auto Post thumbnail」がアップデートしたりして、対応できなくなったのかもれません。

以上の問題を解決するために、以下をfunction.phpなどに追加します。

//ktai entry のimgにclass wp-image- を追加する
add_filter('ktai_image_link', 'ktai_image_link_add_class', 10, 3);
function ktai_image_link_add_class($html, $id, $size){
    return preg_replace('/(<img.*? class=".*?)(".*?\/>)/', '$1 wp-image-' . $id . '$2', $html);
}
//ktai entry で、publish_phone が実行されたときに、auto post thumbnail を起動する
if ( function_exists ( 'apt_publish_post' )) {
    add_action('publish_phone', 'apt_publish_post', 10, 1);
}

これで、メールに添付した画像がサムネイルに設定できるようになりました。

なお、これ以外の解決策として、「JetPack」を使う方法や、「Postie」というプラグインもあります。「Ktai Entry」は古いプラグインで更新もされておらず、使いたくない場合もあるのですが、「Ktai Entry」をどうしても継続して使いたい場合、使わざるをえない場合はこれで。

0

[C#]DataGridViewの変更をDataTableに反映させる

DataGridViewに次のようにチェックボックスを作ってあるとします。

            DataColumn _dc1 = new DataColumn("check", typeof(bool));
            DataColumn _dc2 = new DataColumn("name", typeof(string));
            DataColumn _dc3 = new DataColumn("age", typeof(uint));
            DataTable _dt = new DataTable();
            _dt.Columns.Add(_dc1);
            _dt.Columns.Add(_dc2);
            _dt.Columns.Add(_dc3);
            DataGridView dgv = new DataGridView();

            DataRow _dr = _dt.NewRow();
            _dr["name"] = "本田";
            _dr["age"] = 31;
            _dt.Rows.Add(_dr);

            _dr["name"] = "香川";
            _dr["age"] = 28;
            _dt.Rows.Add(_dr);

            _dr["name"] = "長友";
            _dr["age"] = 30;
            _dt.Rows.Add(_dr);
            
            _dr["name"] = "吉田";
            _dr["age"] = 28;
            _dt.Rows.Add(_dr);

            dgv.DataSource = _dt;

で、DataGridViewに表示されたチェックボックスをつけたあとに、次のように取得しようとしても、最後にチェックしたひとつが取得できていません。

            DataRow[] _selected_rows 
                = ((DataTable)dgv.DataSource).Select("check=true");

そこで、登場するのがEndEdit()。

DataGridViewを操作し始めると、自動的にBigenEdit()メソッドが呼び出されているらしく、それを終わらせるためにEndEdit()を呼び出さないといけないそうです。

というわけで、DataGridViewと、バインドされているDataSourceのDataRowViewでEndEdit()メソッドを実行すればいいと。

            dgv.EndEdit();
            ((DataRowView)dgv.CurrentRow.DataBoundItem).EndEdit();


            DataRow[] _selected_rows 
                = ((DataTable)dataGridView_dataList.DataSource).Select("check=true");
0

MySQL 重複するデータの取得

MySQLで重複した値をもつ行を取得する方法

まずは、データを作るところから。

CREATE TABLE test ( id BIGINT NOT NULL , name TEXT NOT NULL , age SMALLINT NOT NULL ) ENGINE = InnoDB;
INSERT INTO test (id, name, age) VALUES ('1', 'nagatomo', '31');
INSERT INTO test (id, name, age) VALUES ('2', 'yoshida', '28');
INSERT INTO test (id, name, age) VALUES ('3', 'honda', '30');
INSERT INTO test (id, name, age) VALUES ('4', 'okazaki', '31');
INSERT INTO test (id, name, age) VALUES ('5', 'kagaawa', '28');
INSERT INTO test (id, name, age) VALUES ('6', 'usami', '25');
INSERT INTO test (id, name, age) VALUES ('3', 'kubo', '23');

そして、idが重複しているデータをピックアップします。

mysql> SELECT * FROM test GROUP BY id HAVING COUNT(*) >= 2;

 HAVING COUNT(*) >= 2 で、2つ以上重複している行だけをピックアップします。

 

0

MySQL 条件つきでCOUNT、SUM、AVGする

SELECT分で、WHEREで条件を指定して取り出したデータを、COUNTしたり、SUM(合計)したり、AVG(平均)したりする方法。

まずは、サンプルデータを作ります。

CREATE TABLE test ( id BIGINT , name TEXT , age SMALLINT ) ;
INSERT INTO test (id, name, age) VALUES ('1', 'nagatomo', '31');
INSERT INTO test (id, name, age) VALUES ('2', 'yoshida', '28');
INSERT INTO test (id, name, age) VALUES ('3', 'honda', '30');
INSERT INTO test (id, name, age) VALUES ('4', 'okazaki', '31');
INSERT INTO test (id, name, age) VALUES ('5', 'kagaawa', '28');
INSERT INTO test (id, name, age) VALUES ('6', 'usami', '25');

ここから、ageの数、合計、平均を取得します。

/*全数*/
SELECT COUNT(*) FROM test;

/*全合計*/
SELECT SUM(age) FROM test;

/*全平均*/
SELECT AVG(age) FROM test;

つぎに条件付きで取得する場合。以下の例では、30才以上の数、合計、平均を取得します。

/*30才以上の人数*/
SELECT COUNT(age>=30 OR NULL) FROM test;

/*30才以上の合計*/
SELECT SUM(CASE WHEN age>=30 THEN age ELSE 0 END) FROM test;

/*30才以上の平均*/
SELECT SUM(CASE WHEN age>=30 THEN age ELSE 0 END)/COUNT(age>=30 OR NULL) FROM test;

COUNTは単にCOUNT(age>=30)だと、ちゃんと数えてくれません。なんでも、COUNTは()内の結果が、TRUEでもFALSEでも1としてカウントしてしまうからだそうです。
つまり、TRUEかNULLかでカウントしなければならんということです。

TRUE → 1
FALSE → 1

ということで、 OR NULLをつけるとうまくいくというけれど、なんで?
というのを、検証してくださっている方がいて、結論から言うと、FALSEをNULLに変換しているわけですが、そのロジックはというと、

TRUE OR NULL → TRUE → 1
FALSE OR NULL → NULL → 0

となるからだそうです。

というわけで、 OR NULL とすることで、TRUEのときにはTRUE、FALSEのときにはNULLとなって、COUNT(age>=30 OR NULL) でちゃんとうまくいくと。

つぎにSUM()ですが、CASE WHEN文を使えばいいそうです。
ちなみに、SUM(age>=30 OR NULL) とやると、COUNTと同じ結果がかえってきます。TRUEなら1ってことで1×数なので、そりゃそうか。

つぎに平均ですが、AVG()にもCASE WHEN文は使えますが、平均する母数はそのままなので、「30才以上の平均」とはなりません。(サンプルデータだと、(31+30+31)÷6 となってしまいますので、SUMとCOUNTの組み合わせで平均を計算します。

ちなみに、OR NULL や、CASEを使わずに、IFを使ってもできます。こんな感じで。

/*30才以上の人数*/
SELECT COUNT(IF( age>=30 , age , null )) FROM test;

/*30才以上の合計*/
SELECT SUM(IF( age>=30 , age , 0 )) FROM test;

/*30才以上の平均*/
SELECT SUM(IF( age>=30 , age , 0 )) / COUNT(age>=30 OR NULL) FROM test;

/*30才以上の平均*/
SELECT SUM(IF( age>=30 , age ,0 )) / COUNT(IF( age>=30 , age , null )) FROM test;	

以上、取得したデータから条件で数、合計、平均を取り出せますが、実際、この程度のデータと条件であれば、WHERE句で age>=30 とすればいいのですが、たとえば、30以上と、30未満の合計などを一度に取得したいときは、スマートに記述できていいです。こんな感じで。

/*30才以上の人数*/
SELECT COUNT(age>=30 OR NULL) as above30 , COUNT(age<30 OR NULL) as under30 FROM test;

/*30才以上の合計*/
SELECT SUM(CASE WHEN age>=30 THEN age ELSE 0 END) as above30 ,
	SUM(CASE WHEN age<30 THEN age ELSE 0 END) as under30
	FROM test;

/*30才以上の平均*/
SELECT SUM(CASE WHEN age>=30 THEN age ELSE 0 END) / COUNT(age>=30 OR NULL) as above30 ,
	SUM(CASE WHEN age<30 THEN age ELSE 0 END) / COUNT(age<30 OR NULL) as under30
	FROM test;

参考になったサイトさん:
COUNT:https://www.softel.co.jp/blogs/tech/archives/3267
SUM:http://d.hatena.ne.jp/deeeki/20090521/sumcasewhen
AVG:https://blogs.yahoo.co.jp/warp_green_3/23908557.html

0

C# ダイアログフォームのOKボタンをクリックしてもフォームを閉じない

ダイアログを作って、AcceptButtonプロパティに設定したOKボタンをクリックすると、そのダイアログフォームは閉じてしまいますが、条件が整っていないときは、OKボタンを押しても閉じないようにするには次のようにします。

checkbox1にチェックがついていなければ、OKボタンを押しても閉じることはできません。

        private void button_OK_Click(object sender, EventArgs e)
        {
            if (checkbox1.Checkd == false)
            {
                close_permition = false;
            }
        }

        bool close_permition = true;

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!close_permition)
            {
                close_permition = true;
                e.Cancel = true;
            }
        }

OKボタンを押したときだけ、checkbox1を確認してその結果をclose_permitionに保存します。

FormClosingイベントで、close_permitionがfalseなら、
e.Cancel = true として、フォームを閉じることをキャンセルします。

単に、

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (checkbox1.Checkd == false)
            {
                e.Cancel = true;
            }
        }

としてしまうと、キャンセルボタンや、閉じるボタンをクリックしたときに、checkbox1の影響を受けてしまうので、前述のようにしないといけないよ。というお話でした。

0

Master Slider でページボタンをオンマウスで表示する

スライドショーのプラグインとして、とても使い勝手のいい、Master Sliderを使っているのですが、左右にスライドさせるためのボタンが大きくて、肝心のバナーを隠してしまっているので、マウスポインターが上に来た時だけ、常時させるようにする方法。

CSSや、JQueryで、hoverを使うと、うまく表示非表示を切り替えられなかったので、マウスポインタの座標と、スライダーの座標をチェックして、範囲内にあれば、ボタンを表示、範囲外なら非表示となるようにしています。

jQuery(function($) {
    $(document).ready(function () {
        var show = 0;
        $(window).mousemove(
            function(e){
                var offset = $(".ms-container").offset();
                var mswidth = $(".ms-container").width();
                var msheight = $(".ms-container").height();
                console.log('top: ' + offset.left + mswidth );
                console.log('top: ' +  e.pageX );
                if(offset.left < e.pageX
                        && (offset.left + mswidth) > e.pageX
                        && offset.top < e.pageY
                        && (offset.top + msheight) > e.pageY
                ){
                    $(".ms-nav-next ,  .ms-nav-prev ").show();
                }else{
                    $(".ms-nav-next ,  .ms-nav-prev ").hide();

                }
            }
        );
    });
});
0

inkscapeでDXFデータを出力する

「NC工作機械で加工したいので、絵をDXFデータにできない?」という相談がありまして、とりあえず、Inkscape(ver.0.91)でトライすることに。

まずは、下絵をInkscapeに貼り付けて、その上をトレース。

そして、「名前をつけて保存」で保存形式をDXFにして保存しようとすると、なぜかエラーに。

そこで、調べてみたところ、次のようにすればいいことがわかりました。

  1. 「名前をつけて保存」のときに、プレーンSVGで一旦保存する。
  2. 保存したプレーンSVGをInkscapeで読み込む
  3. 「名前をつけて保存」で保存形式をDXFにして保存

他にも試してだめだったこと

他にも、Inkscape(ver.0.91)を0.92にバージョンアップすればいいのか、と試してみましたが、だめでした。

また、プレーンSVGをフリーツールで変換しようとしましたが、これもだめでした。
試したのは、

convertio
https://convertio.co/ja/svg-dxf/

VectorToVector
http://www.vector.co.jp/soft/win95/business/se438196.html

いずれで変換しても、ちゃんと変換できませんでした。

 

0