C# iTextSharpで枠内に収まるようにテキストを出力

iTextSharpでSetSimpleColumnを使って、指定した枠内にテキストを収めたい場合、フォントサイズを小さくするしかありません。

そこで、徐々にフォントサイズを小さくしながら、枠内に収まるようにテキストを描画する方法です。
columnText.Go()で描画するのですが、columnText.Go(true)と引数にtrueを渡すことで、シミュレーションモドになります。で、戻り値をみると、枠内に文字が収まったかどうかがわかります。

もし、戻り値がColumnText.NO_MORE_COLUMNなら、枠外にはみ出ていることになります。
なので、戻り値がColumnText.NO_MORE_COLUMNである間は、フォントサイズを小さくしていくようにします。

ただし、フォントサイズがあまりにも小さいと見えなくなってしまうし、マイナスになると例外を発生するので、1.0f以下にはならないようにします。

以下のサンプルコードは、
using System.IO;
using iTextSharp.text.pdf;
using iTextSharp.text;
を必要とします。

//A4サイズを横向きで
Document pdfDocument = new Document(PageSize.A4.Rotate(), 0, 0, 0, 0);

//出力先のファイル名
string makePdfFilePath = @"c:\PDF\test.pdf";
FileStream fileStream = new FileStream(makePdfFilePath, FileMode.Create);
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, fileStream);

//パスワードで保護する場合
//string password = "pass";
//pdfWriter.SetEncryption(Encoding.ASCII.GetBytes(password), Encoding.ASCII.GetBytes(password),
//    PdfWriter.ALLOW_SCREENREADERS, PdfWriter.STANDARD_ENCRYPTION_128);

//PDFドキュメントを開く
pdfDocument.Open();

//フォント名
string fontName = "MS ゴシック";

//フォントスタイル。 複合するときは、&で。
int fontStyle = iTextSharp.text.Font.BOLD;// &iTextSharp.text.Font.ITALIC;

//フォントカラー
BaseColor baseColor = BaseColor.BLACK;

PdfContentByte pdfContentByte = pdfWriter.DirectContent;

//テンプレートとするPDF
//PdfReader pdfTemplateReader = new PdfReader(@"c:\PDF\BlankSheet.pdf"); 
//PdfImportedPage pdfTemplatePage = pdfWriter.GetImportedPage(pdfTemplateReader, 1);
//pdfContentByte.AddTemplate(pdfTemplatePage, 0, 0);

//フォントファイルのシステムフォルダを設定
FontFactory.RegisterDirectory(Environment.SystemDirectory.Replace("system32", "fonts"));

//出力するテキスト
string draw_text = "テキスト出力テキスト出力";

//文字間を指定
pdfContentByte.SetCharacterSpacing(0.1f);

//出力する位置
float draw_x = 50;
float draw_y = 50;
float draw_w = 150;
float draw_h = 20;

//四角を出力
//線の色を指定
pdfContentByte.SetRGBColorStroke(255, 0, 0);
//線の幅を指定
pdfContentByte.SetLineWidth(1.0f);
//線の種類(点線)を指定
pdfContentByte.SetLineDash(5.0f, 2.0f);
//範囲
pdfContentByte.Rectangle(draw_x, draw_y, draw_w, draw_h);
//描画
pdfContentByte.Stroke();

//範囲内に収まるようにフォントサイズを小さくしていく
for (float fontSize = 30.0f; fontSize > 0; fontSize--)
{
    //フォントの設定
    iTextSharp.text.Font font =
        FontFactory.GetFont(fontName,
        BaseFont.IDENTITY_H,            //横書き
        BaseFont.NOT_EMBEDDED,          //フォントを組み込まない
        fontSize,
        fontStyle,
        baseColor);

    
    ColumnText columnText = new ColumnText(pdfContentByte);

    //SetSimpleColumnで出力
    columnText.SetSimpleColumn(
        new Phrase(draw_text, font)
        , draw_x
        , draw_y
        , draw_x + draw_w
        , draw_y + draw_h
        , fontSize
        , Element.ALIGN_LEFT    //ちなみに、SetSimpleColumnでは、ALIGN_MIDDLE(縦方向の中寄せ)は使えない
        );

    //テキスト描画シミュレーション
    int result = columnText.Go(true);

    //もし、枠内に収まっていなければ、columnText.Go() の戻り値はColumnText.NO_MORE_COLUMNになる
    if (ColumnText.NO_MORE_COLUMN != result || fontSize <= 1.0f)
    {
        //再度、columnTextにテキストをセット
        columnText.SetSimpleColumn(
            new Phrase(draw_text, font)
            , draw_x
            , draw_y
            , draw_x + draw_w
            , draw_y + draw_h
            , fontSize
            , Element.ALIGN_LEFT
            );

        //テキスト描画
        columnText.Go();
        
        break;
    }
}

//PDFドキュメントを閉じる。
pdfDocument.Close();

説明のために、わざとつらつら書いてますが、ところどころ関数化しておくと便利です。

C# iTextSharpで日本語のPDFファイルを出力

PDFファイルを出力するライブラリにiTextSharpがあります。
JAVAライブラリだったiTextを.net用に移植されたものです。(ありがたい!)

iTextSharpを使って、日本語でPDFファイルを出力します。

iTextSharpの準備

まずは、VisualStudioの設定ですが、手軽にnuGetでいきます。

NuGetパッケージマネージャの起動

iTextSharpで検索すればすぐ見つかりますので、インストール。
iTextSharpで検索

OKをクリック。
1607100003

あとは、同意→閉じる で準備完了。

コーディング

まず、以下のサンプルを試す場合は、
using System.IO;
using iTextSharp.text.pdf;
using iTextSharp.text;
を入れておいてください。

テキストを描画する方法はたくさんあるのですが、一番シンプルな方法は次のようにします。ただし、この方法では描画する位置は自由に指定できませんし、日本語を出力できません。(多分)

            //A4サイズを横向きで
            Document pdfDocument = new Document(PageSize.A4.Rotate(), 0, 0, 0, 0);

            //出力先のファイル名
            string makePdfFilePath = @"c:\PDF\test.pdf";
            FileStream fileStream = new FileStream(makePdfFilePath, FileMode.Create);
            PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, fileStream);

            //PDFドキュメントを開く
            pdfDocument.Open();

            pdfDocument.Add(new Paragraph("test"));
            
            //PDFドキュメントを閉じる
            pdfDocument.Close();

 

ShowTextでテキスト描画

今度は、任意の場所にテキストを配置する場合。
上と違って、PdfContentByte オブジェクトを先に用意して、MoveText(50, 50) で描画位置を指定しています。ちなみに、左下が(0,0)です。
pdfDocument.Add()で描画すると、左上から始まるくせに、左下が(0,0)とはなんぞ。という感じですが。

//A4サイズを横向きで
Document pdfDocument = new Document(PageSize.A4.Rotate(), 0, 0, 0, 0);

//出力先のファイル名
string makePdfFilePath = @"c:\PDF\test.pdf";
FileStream fileStream = new FileStream(makePdfFilePath, FileMode.Create);
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, fileStream);

//PDFドキュメントを開く
pdfDocument.Open();

string fontFolder = Environment.SystemDirectory.Replace("system32", "fonts");

//フォント名
string fontName = fontFolder + "\\msgothic.ttc,0";

//フォントカラー
BaseColor baseColor = BaseColor.BLACK;

//フォントサイズ
float fontSize = 30.0f;

PdfContentByte pdfContentByte = pdfWriter.DirectContent;

//フォントの準備
BaseFont baseFont = BaseFont.CreateFont(fontName, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

//テキスト描画開始
pdfContentByte.BeginText();

//フォントとフォントサイズの指定
pdfContentByte.SetFontAndSize(baseFont, fontSize);

//描画位置の指定
pdfContentByte.MoveText(50, 50);

//描画するテキスト
pdfContentByte.ShowText(new PdfTextArray("あいうえお"));
pdfContentByte.ShowText(new PdfTextArray("かきくけこ"));

//テキスト描画終了
pdfContentByte.EndText();

//PDFドキュメントを閉じる
pdfDocument.Close();

SimpleColumnを使って、任意の枠内にテキスト描画

ColumnTextのSetSimpleColumnメソッドを使えば、指定した枠内にテキストを描画できます。
フォントの指定方法を上の例ではFontBaseを使っていますが、以下ではFontFactoryでpdf.Fontを取得して指定しています。フォントはファイル名ではなくフォント名を指定します。

//A4サイズを横向きで
Document pdfDocument = new Document(PageSize.A4.Rotate(), 0, 0, 0, 0);

//出力先のファイル名
string makePdfFilePath = @"c:\PDF\test.pdf";
FileStream fileStream = new FileStream(makePdfFilePath, FileMode.Create);
PdfWriter pdfWriter = PdfWriter.GetInstance(pdfDocument, fileStream);

//PDFドキュメントを開く
pdfDocument.Open();

//フォント名
string fontName = "MS ゴシック";

//フォントサイズ
float fontSize = 10.0f;

//フォントスタイル。 複合するときは、&で。
int fontStyle = iTextSharp.text.Font.BOLD;// &iTextSharp.text.Font.ITALIC;

//フォントカラー
BaseColor baseColor = BaseColor.BLACK;

//Fontフォルダを指定
FontFactory.RegisterDirectory(Environment.SystemDirectory.Replace("system32", "fonts"));

//フォントの設定
iTextSharp.text.Font font =
    FontFactory.GetFont(fontName,
    BaseFont.IDENTITY_H,            //横書き
    BaseFont.NOT_EMBEDDED,          //フォントを組み込まない
    fontSize,
    fontStyle,
    baseColor);

PdfContentByte pdfContentByte = pdfWriter.DirectContent;

ColumnText columnText = new ColumnText(pdfContentByte);

//SetSimpleColumnで出力
columnText.SetSimpleColumn(
    new Phrase("あいうえおかきくけこ", font)
    , 50    // X1位置
    , 50    // Y1位置
    , 100   // X2位置
    , 70    // Y2位置
    , fontSize
    , Element.ALIGN_LEFT    //ちなみに、SetSimpleColumnでは、ALIGN_MIDDLE(縦方向の中寄せ)は使えない
    );

//テキスト描画
columnText.Go();

//PDFドキュメントを閉じる
pdfDocument.Close();

 

C# 配列やListで任意の範囲を合計したり、平均出したり。

配列で、合計を出したければ Sum()、平均を出したければ Average() メソッドが便利ですが、配列の特定の範囲だけを対象にしたい場合。

Array.Copy()で任意の範囲を抜き出す

たとえば、次のように8つの要素がある配列の2番目から5つの要素の合計や、平均を求めたい場合、Array.Copy()を使って、一旦別の配列に抜き出してから、その配列を合計、平均すればいいです。

  int[] a = new int[] { 85, 76, 68, 79, 82, 65, 72, 74 };

 //int型の配列の合計
 int a_sum = a.Sum();

 //int型の配列の平均
 double a_avg = a.Average();

 
 //配列の1つ目から5つを抜き出す
 int[] b = new int[5];
 Array.Copy(a, 1, b, 0, 5);

 //抜き出したint型の配列の合計
 int b_sum = b.Sum();

 //抜き出したint型の配列の平均
 double b_avg = b.Average();

上の例では、Array.Copy(c, 1, d, 0, 5); で、List<int> c の1つ目から配列のコピーを、bのはじめ(0)から5つ分配置する。ということになります。

List型ではCopyTo()で同様に処理できる

ところが、Array.Copy()はプリミティブ型(基本形)の配列しか扱えません。
でも、List型のようなCollection系の配列の場合、CopyTo()が使えるので同じように処理できます。

以下の例では、

  List<int> c = new List<int> { 85, 76, 68, 79, 82, 65, 72, 74 };

 //List<int>型の合計
 int c_sum = c.Sum();

 //List<int>型の平均
 double c_ave = c.Average();

 int[] d = new int[5];

 c.CopyTo(1, d, 0, 5);

 //抜き出したint型の配列の合計
 int d_sum = d.Sum();

 //抜き出したint型の配列の平均
 double d_avg = d.Average();

a.CopyTo(1, b, 0, 5); で、List<int> a の1つ目から配列のコピーを、bのはじめ(0)から5つ分配置する。ということになります。

似てますけど、微妙に違うので混乱してしまいそうなのでメモ。

C# DataGridViewRowをDataRowに変換する方法

DataGridViewのDataSourceにDataTableをセットしているとき、DataGridViewRowをDataRowに変換する方法。

_dataGridView というDataGridViewがあるとして、

DataGridViewRow _dgvr = _dataGridView.Rows[0];
DataRowView _drv = (DataRowView)_dgvr.DataBoundItem;
DataRow _dr = (DataRow)_drv.Row;

とすれば変換できます。

 

C# DataTableに任意のColumnがあるか調べる

C# のDataTableで特定のカラムがあるか、有無を調べるには、Columns.Containsを使います。

DataTable _dt = new DataTable();
DataColumn _dc_name = new DataColumn("name");
DataColumn _dc_age = new DataColumn("age");
_dt.Columns.AddRange(new DataColumn[] { _dc_name, _dc_age });

if (_dt.Columns.Contains("age"))
{
    //処理
}

簡単ですな。

 

CSS 途中で要素を画面いっぱいに広げる

ヘッダーや、フッターを画面いっぱいに広げる場合、widthを100%に指定すればいいだけですが。

1607010001

mainの途中で背景だけ目一杯に広る場合、mainを2つに分けて、間に目一杯の枠を作る。なんてことをしてた時期がありまして。こんな感じで。

1607010003

非常に効率が悪かったわけですが、できればこんなふうにmainの途中でも画面いっぱいに広がる枠を入れられたら楽ですよね。こんな感じで。

1607010002

で、どうするかというと、意外と簡単で、広げたい部分をdiv要素で囲って、
幅方向のmarginにマイナスの値を設定して、マイナス分を、paddingで補います。

margin:0 -200%;
padding:0 200%;

とすれば、いいわけですが、それだけだと、はみ出た部分まで表示しようとスクロールバーが出てきてしまいます。なので、bodyに

overflow-x: hidden;

を適用すればいいのですが、なぜかiPhoneなどで画面を横向けにすると、bodyに適用したはずのoverflow-x: hidden の効果がでません。なので、bodyのすぐ内側に全体を囲むdiv要素を追加して、その要素にoverflow-x: hidden を適用します。

ポイントは、marginの幅に-200%、paddingの幅に200%を指定していて、このおかげで横幅いっぱいに広がります。
このままだと、内容物が外に出て行ってしまうので、text-alignでセンタリングします。
あと、bodyにoverflow-x: hidden;を指定してますが、こうしないとスクロールバーが出てきてしまうからです。

ここだけ目一杯広げる

参考になりました。http://css-eblog.com/csstechnique/overflow-menu.html

Office2013 英語版を日本語表記にしたい

裏ワザ的に、評価版のOffice2013日本語版や、Office2013日本語版のDVDがあれば、英語版をアンインストールしてから、日本語版をインストールしなおして、ライセンスキーは英語版のものを入れる。という手もあるようです。

ですが、結論からいうと、インストール済みのOffice2013英語版を日本語表記にするには、言語パックを購入して適用するしか手はありません。

https://www.microsoftstore.com/store/msjp/ja_JP/pdp/productID.266844700?lang=japanese

ちなみに、
https://technet.microsoft.com/ja-jp/library/cc179115.aspx#BKMK_LanguageInterfacePacks
をみると、LIP (Language Interface Pack)なら無料っと書いてあるけれど、LIPに日本語は含まれていません。なので、実質インストール済みのOffice2013英語版を日本語表記にするには、言語パックを購入するしか手はありません。

で、依頼のあったパソコンのOffice2013に言語パックを手に入れてインストーラを起動しようとしたのですが、なぜかインストール中の表示は出てこず、何事もなかったようになります。おかしいな、となんどか繰り返したのですが、ふとみるとOffice2013は日本語化されていました。

Office2010は言語パックの配布を終了しているようです。

 

Windowsでキーボードの配列がおかしくなった時の修正方法

Windwos7 Professionalを、英語版のWindwos7 Enterpriseにアップデートしたようで、その際にキーボードの配列がおかしくなったので見て欲しいと依頼がありました。

で、見てみると、一部のキーボードのキーに書いてある文字と、押して表示される文字が違うという現象が起きていました。特に記号関係のキーはめちゃくちゃ。

これは、使用しているキーボードが106配列(日本語)なのに、101配列(英語)として設定されているためです。
というわけで、解決策。

答えはマイクロソフトのオフィシャルページにあります。

https://support.microsoft.com/ja-jp/kb/927824

で、今回はレジストリを編集して対応できました。
以下、その方法ですが、レジストリは下手にいじると、致命的な問題が発生して、Windwosが起動しなくなってしまう場合もあります。とはいえ、必要な項目だけを間違えずに修正すればよく、それほど難しいものではないので、必要以上にビビる必要はないかと。

レジストリエディタを開く

まずは、レジストリエディタを開きます。

コマンドプロンプトで、regedit と入力します。
コマンドプロンプトは、Windows7なら、スタート→すべてのプログラム→アクセサリ に大抵入っています。
Windows8なら、すべてのアプリで、Windowsシステム ツールにあります。

regedit

レジストリ値を修正する

レジストリエディタが開いたら、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters
を開きます。

HKEY_LOCAL_MACHINE をクリックすればツリーが開くので、SYSTEMをクリック。そしたら、今度はCurrentControlSetをクリック。という感じで順に開いていきます。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

i8042prtを開くと、Parametersがあって、そこをクリックすると目的のレジストリが表示されます。(この画面はWindwos8の場合です。ちなみに、LayerDriver KORというのは、韓国語用のレジストリキーなので、関係ありません。(削除した方がいい場合もあるようです)

i8042prt\Parameters

修正が必要なのは

LayerDriver JPN
OverrideKeyboardIdentifier
OverrideKeyboardSubtype
OverrideKeyboardType

の、4箇所。
一つづつ、修正します。
修正するレジストリの名前のうえで、マウスの右ボタンをクリックし、修正(M)をクリックします。
レジストリ値の修正
LayerDriver JPN がおそらく、kbd101.dllになっているので、kbd106.dll に修正。
1606240013

OverrideKeyboardIdentifier はPCAT_101KEYになっているので、PCAT_106KEYに修正。
1606240014

OverrideKeyboardSubtype は、2、に修正します。
1606240015 

OverrideKeyboardType は7ですが、おそらく修正はいらないと思います。
1606240008

修正が終わったら、ファイル(F)→レジストリエディタの終了(X)をクリック。
1606240009

Windwosの再起動

あとはWindowsを再起動し、キーボードが正しく操作できるか確認してみてください。

 

 

ブルートフォースアタック(総当り攻撃)を狙われた痕跡

 

ブルートフォースアタック(総当り攻撃)を狙われた痕跡がログに残っていました。

37.252.2.101 - - [22/Jun/2016:06:31:30 +0900] "GET /wp-login.php HTTP/1.1" 403 214 "http://accelboon.com/wp-login.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:32 +0900] "GET /blog//wp-login.php HTTP/1.1" 404 216 "http://accelboon.com/blog//wp-login.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:34 +0900] "GET /administrator/ HTTP/1.1" 404 212 "http://accelboon.com/administrator/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:34 +0900] "GET /blog//administrator/ HTTP/1.1" 404 218 "http://accelboon.com/blog//administrator/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:35 +0900] "GET /admin.php HTTP/1.1" 404 207 "http://accelboon.com/admin.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:35 +0900] "GET /blog//admin.php HTTP/1.1" 404 213 "http://accelboon.com/blog//admin.php" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:36 +0900] "GET /bitrix/admin/ HTTP/1.1" 404 211 "http://accelboon.com/bitrix/admin/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:36 +0900] "GET /blog//bitrix/admin/ HTTP/1.1" 404 217 "http://accelboon.com/blog//bitrix/admin/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:37 +0900] "GET /?q=user HTTP/1.1" 200 11413 "http://accelboon.com/?q=user" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:39 +0900] "GET /blog//?q=user HTTP/1.1" 404 204 "http://accelboon.com/blog//?q=user" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:40 +0900] "GET /index.php/admin/ HTTP/1.1" 301 - "http://accelboon.com/index.php/admin/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:41 +0900] "GET /admin/ HTTP/1.1" 404 204 "http://accelboon.com/admin/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"
37.252.2.101 - - [22/Jun/2016:06:31:53 +0900] "GET /admin/ HTTP/1.1" 404 204 "http://accelboon.com/admin/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"

/wp-login.php
/blog//wp-login.php
/administrator/
/blog//administrator/
/admin.php
/blog//admin.php
/bitrix/admin/
/blog//bitrix/admin/
/?q=user
/blog//?q=user
/index.php/admin/
/admin/
/admin/

という感じで、プログラム的に入り口を探られた痕跡があります。

残念ながら(?)Wordpress本体はサブフォルダにインストールしているので、wp-adminは見つからなかったみたいですね。
でも、人間の目で見れば見つかっちゃうんですけどね。

というわけで、もしログイン画面がみつかって、ブルートフォースアタック(総当り攻撃)されないために対策。

WordPressのログイン画面に文字認証CAPTCHA)を追加する

まず、SI CAPTCHA Anti-Spamプラグイン をインストールします。
SI CAPTCHA Anti-Spam はAnti-Spamが示す通り、コメントスパム対策のためのプラグインなのですが、ログイン画面にも文字認証(CAPTCHA)を追加できます。

プラグインをインストールしただけでは、ログイン画面には文字承認は表示されません。
プラグインをインストール後に設定が必要です。

SI CAPTCHA Anti-Spamの設定

SI CAPTCHA Anti-Spamプラグインをインストールしたら、プラグインのところに、SI Captchaオプション 項目が追加されますので、そこをクリック。

SI Captcha Option

□ログインフォームでキャプチャを有効にする。 にチェックをつけて、[オプション更新] ボタンをクリックします。

ログインフォームでキャプチャを有効にする。

これでログイン画面に文字認証(CAPTCHA)が追加されます。

文字認証(CAPTCHA)

Advanced Custom Fieldsで選択肢が複数のフィールドをWP_Queryで取り出す

Advanced Custom Fields を使って、カスタムフィールドを活用することが多いのですが、フィールドタイプに「関連」を使うと、ある投稿に関連する、別の投稿を登録することができます。

Advanced Custom Fields のフィールドタイプ

で、その値は、get_field()で取り出すことができます。

$page_id = 16534;
$relation_page_id_list = get_field($page_id , 'relation')
print_r(relation_page_id_list);

戻り値は、配列なので、
Array ( [0] => 12130 )
となります。

WP_Queryで関連元を取り出す

これはこれでOKなのですが、今度は逆に、関連とされた投稿から、関連元を取り出す必要がある場合。

WP_Queryでmeta_keyとmeta_valueに値を入れて取り出すことになるのですが、

$shop_id = 12130;
$args = array (
	'posts_per_page' => 5,
	'post_type' => 'post',
	'post_status' => 'publish',
	'meta_key' => 'relation',
	'meta_value' => $shop_id,
);
$query = new WP_Query($args);

これでは取り出せません。
そもそも、get_field()で取り出した値が配列な時点で、無理だろうなー、と思うのですが案の定ですね。

では、そもそも、「関連」フィールドで保存されたmeta_valueはどんな形なのかというと、

$page_id = 16534;
$table = $wpdb->prefix . "postmeta";
$shops_id = $wpdb->get_results( "SELECT post_id , meta_value FROM $table WHERE meta_key = 'shopspage' AND post_id = " . $page_id , ARRAY_A);
print_r ($shops_id);

と直接SELECTをたたいてみるとこんな感じで、meta_valueには、シリアライズされたデータで保存されてることがわかります。

Array ( [0] => Array ( [post_id] => 16534 [meta_value] => a:1:{i:0;s:5:"12130";} ) )

なので、普通に、meta_valueで検索しても引っかかりません。
ではどうすればいいかというと、meta_valueそのものは文字列なので、LIKEで見つければいいのではと。

$shop_id = 12130;
$args = array (
	'posts_per_page' => 1,
	'post_type' => 'post',
	'post_status' => 'publish',
	'meta_key' => 'relation',
	'meta_value' => '"' . $shop_id . '"',
	'meta_compare' => 'LIKE',
);
$query = new WP_Query($args);

これで関連元のページ一覧を取得できます。

ちなみに、

'"' . $shop_id . '"'

と、わざわざダブルクォーテーションで囲っているのは、たとえば12130 は 121、1213、2130なんかでも引っかかってしまうからです。