Advanced Custom Fields でカスタムフィールドの値が更新できない

前置き

大量のデータを一括で入れたいとき、Really Simple CSV Importer が便利なのですが、
さらに、画像も一括で取り込みたいときは、Really Simple CSV Importer Media Plus を使うと幸せになれるわけです。

ついでに、カスタムフィールドも Advanced Custom Fields を使っていて、あらかじめ、サーバー上にまとめて画像を上げておいて、それを一括で取り込むようにエクセルなんかでCSVファイルを用意して、一気呵成に取り込んだわけですが、ここから本題。

本題

Advanced Custom Fields で用意しておいた、画像のフィールド、たとえば photo2 としましょう。
そこに一括で画像を登録するところまではうまくいったのですが、どういうわけか、WordPressの管理画面から、なんどやっても内容を更新できなくなっていることに気が付きました。

管理画面では、カスタムフィールドの画像はきれいに入れ替わっているはずなのに、フロント側では表示されなかったり、古いままの画像が表示されたり。

これはいったいなんだ。と延々と悩んだ末、とんでもない結末が。。。

結論

1612270001

もう、なんだか大変申し訳無い気持ちでいっぱいなのですが、カスタムフィールド名の前に、半角の空白が、ひっそりと入っていました。

この空白をクリアすればそれだけで問題は解決。

ぐはぁ。

なぜ、これに気がついたかというと、カスタムフィールドの値が格納されている、wp_postmetaテーブから、投稿(カスタム投稿)に関連するデータをぜんぶ引っ張り出してみる。こんなかんじで。

 

<?php
	if (is_user_logged_in()){
	    global $wpdb;
	    $sql = "SELECT * FROM $wpdb->postmeta WHERE post_id=" . $post->ID;
	    $results = $wpdb->get_results( $sql, OBJECT );
	    print_r($results);
	}
?>

これをsingle.php なりに貼り付けてみてみると、

[meta_key] => photo2 というのと、

[meta_key] => _ photo2 というのがあって、この空白入りのやつが怪しいと。

アンスコが先についているのが、Advanced Custom Fields 固有のデータで、それとアンスコなしの本来のカスタムフィールドのデータが連動していると。

ところが、アンスコを消すと、先頭に空白がつくので、それがなくなってしまって、整合性がとれなくなるということでした。

_ photo2から、photo2は取り出せるけれど、その逆はできない(photo2→_photo2)という感じでしょうか。

だから、管理画面では違う画像に入れ替えたらちゃんと変わるのに、フロント側では表示されないというわけですね。

なお、Advanced Custom Fields のフィールド名を後から変更すると、変更前に保存された古いフィールド名のデータはそのまま残骸として残ってしまうようです。

実際には動作上はあまり問題はなってませんfいようですが、きになるなら

$sql = "DELETE FROM wp_postmeta WHERE meta_key='_ photo2'";
$results = $wpdb->query( $sql );

という感じで一括削除出来ると思います。自己責任で。

そもそも、Advanced Custom Fields のフィールド名を入力する段階で気をつけておかないといけないことですね。

 

WordPressのメディアをカテゴリー分けするプラグイン

WordPressのメディアに入れた、画像などのデータをカテゴリー分けして、検索できるようにするプラグイン。

WordPressは、デフォルトではメディアにたまった画像などは累々と貯まるようになっていて、メディアの一覧から目的の画像を探し出すのは意外と面倒です。

たとえば、フォトコンテストなんかで募集した写真を掲載するときに、記事中に使っている画像とごっちゃになると、あとから確認する際なんかに探し出すのが大変なので、カテゴリ分けしておきたいな。という場合には、さくっとプラグインで対応できます。

メディアをカテゴリ分けするプラグインにも、いくつかあるので、まとめ。

Media Library Categories

紹介する3つの中ではダントツでシンプルなプラグイン。とりあえず、カテゴリー分けできたらなんでもいい。という場合はこれかな。

投稿で使うカテゴリーとおなじタクソノミー、つまりWordPress標準のカテゴリーで分類します。

特に設定はなく、プラグインをインストールしたら、メディアに「カテゴリ」の項目が出てきて、一覧から絞込もできます。カテゴリーの設定は、メディアの編集画面で設定します。

Media Library Categories の絞込操作

Enhanced Media Library

投稿でつかうカテゴリーと、Media Categoriesというカスタムタクソノミーが追加されます。

Enhanced Media Library の検索操作

プラグインをインストールした時点では、絞込ができるのはMedia Categories の方だけです。

じゃ、なんのためのカテゴリー?とも思いますが、設定→メディア→Media Taxonomies→Non-Media Taxonomiesで、Filter for List View、Filter for Grid View / Media Popupにチェックをつけると、カテゴリーでも、絞込、検索ができるようになります。

Enhanced Media Library でのカテゴリーの検索設定

あと、項目を日本語表示にしたければ、設定→メディア→Media Taxonomies→Media Taxonomies で日本語表記の設定をしてあげればOKです。

Enhanced Media Libraryで項目の日本語設定

 

また、[+ Add New Taxonomy]で、独自にカスタムタクソノミーを追加することもできます。

それから、設定→メディア→Media Taxonomies→Media Library→Media Shortcodeで、Enhanced media shortcodes にチェックをつけると、ギャラリーを出力できるようになりますが、Warningで「他のプラグインとかと一緒に使うときは気をつけてね。問題があったら、作者に連絡してね!」なんて言ってるので、おまけ程度に考えておいたほうが良さそうです。

Enhanced Media Library でショートコードが使えるようにする

Media Library Assistant

カテゴリーと、タグがつけられるようになります。

Media Library Assistan の検索操作 Media Library Assistantでは、カテゴリも、タグも、カスタムタクソノミーになっているので、投稿でつかっているカテゴリとタグとは別ものになってます。なので、このプラグインをインストールした時点では、カテゴリーもタグもありません。

検索は、カテゴリやタグで絞込、検索ができるほか、タイトルやキャプションから文字列での検索もできるようになっています。

また、独自の管理機能がついていて、それを使えばクイック編集も出来るようになります。かなり多機能なのですが、英語表記なので、エンドユーザーに使ってもらうにはちょっと難がありますね。

Media Library Assistan の独自管理画面

他にも、設定項目が大量にあって、ショートコードでギャラリーを出力したり、カスタムフィールドを追加したりとできるようです。(あまり詳しく見ていないので、なんとなく)

 

 

WordPress管理画面の一覧でカラムを表示させたい

管理画面で、投稿や固定ページ、カスタム投稿の一覧には、タイトルや投稿者などの項目が並んでいますが、そこにカスタムフィールドを表示させたい場合があります。

今回、ちょっと手こずったところもあったので、それも合せてまとめ。

管理画面の一覧でカラムを表示

まず、管理画面の一覧でカラムを表示させたい場合、
固定ページでは、manage_pages_columns
投稿では、manage_posts_columns
カスタム投稿では、manage_posts_columns、または、manage_${post_type}_posts_columns
を使います。

以下、itemsというカスタム投稿と、item_idというカスタムフィールドがすでにあるとして、それを表示させたい場合。function.phpに以下を追加します。

固定ページでは、

function add_column_name ( $columns ) {
	$columns['item_id'] = "アイテムID";
	return $columns;
}
add_filter( 'manage_pages_columns', 'add_column_name' );

投稿では、

function add_column_name ( $columns ) {
	$columns['item_id'] = "アイテムID";
	return $columns;
}
add_filter( 'manage_posts_columns', 'add_column_name' );

とします。

$columns['item_id'] のitem_id はカスタムフィールド名と一致していなくてもも構いません。また、カスタム投稿は、投稿の一種なので、manage_posts_columnsを使えば、同じように表示されます。

なので、カスタム投稿では表示させたいくない場合、get_post_type を使って、投稿の場合だけに限定する必要があります。

function add_column_name ( $columns ) {
	global $post;
	if (get_post_type( $post ) == 'post'){
		$columns['item_id'] = "アイテムID";
	}
	return $columns;
}
add_filter( 'manage_posts_columns', 'add_column_name' );

カスタム投稿だけに限定したければ、同じように、

function add_column_name ( $columns ) {
	global $post;
	if (get_post_type( $post ) == 'itenms'){
		$columns['item_id'] = "アイテムID";
	}
	return $columns;
}
add_filter( 'manage_posts_columns', 'add_column_name' );

とすればOKです。
または、manage_${post_type}_posts_columns を使って、以下のようにしてもおなじです。

function add_column_name ( $columns ) {
	$columns['item_id'] = "アイテムID";
	return $columns;
}
add_filter( 'manage_items_columns', 'add_column_name' );

さらに、カスタム投稿では、日付を表示する必要が無いという場合。次のようにunsetで削除できます。

次の例は、カスタム投稿が items のときには、dateを削除、ついでに投稿でコメントを非表示にしたいとき。

function add_column_name ( $columns ) {
	global $post;
	if (get_post_type( $post ) == 'items'){
		$columns['item_id'] = "アイテムID";
		unset($columns['date']);
	}
	unset($columns['tags']);
	return $columns;
}
add_filter( 'manage_posts_columns', 'add_column_name' );

ここまでで、一覧に項目が表示されるようになるはずです。

カスタムフィールドの値を一覧に表示させる

続いて、カスタムフィールドの値を表示させるようにします。

投稿、カスタム投稿では、manage_posts_custom_column を使います。
固定ページでは、manage_pages_custom_column を使います。

次の例では、固定ページ、投稿、カスタム投稿すべてに対応します。

//item_idの項目に値を表示
function add_column_value ($column_name, $post_ID) {
	if( $column_name == 'item_id' ) {
		echo get_post_meta($post_ID, 'item_id', true);
		//echo get_post_meta($post_ID, 'wpcf-item_id', true);//カスタムフィールドの作成に、プラグインの「Types」をつかている場合は、wpcf-をつける
	}
}
add_filter( 'manage_pages_custom_column', 'add_column_value', 10, 2 );
add_filter( 'manage_posts_custom_column', 'add_column_value', 10, 2 );

通常、投稿は投稿の日付順、固定ページとカスタム投稿はタイトル順 で並べられて表示されます。
そうではなくて、カスタムフィールドの値順で並べたい場合もあります。そんなときは、pre_get_posts で、is_admin で分岐させて並べ替えます。

表示された一覧を、item_id の順番で表示させたい場合、

//カスタム投稿itemsの一覧を、カスタムフィールドitem_idの値順に並べ替え
function set_post_types_admin_order( $wp_query ) {
	if (is_admin()) {
		$post_type = $wp_query->query['post_type'];
		if ( $post_type == 'items' ) {
			$wp_query->set('meta_key', 'item_id');
			$wp_query->set('orderby', 'meta_value');
			$wp_query->set('order', 'ASC');
		}
	}
}
add_filter( 'pre_get_posts', 'set_post_types_admin_order' );

[まとめ]管理画面で、カスタム投稿の一覧にカスタムフィールドの値を表示させて、その値順に並べ替える

以上、まとめますと、こんな感じになります。

//カスタム投稿にカスタムフィールドの項目を追加
function add_column_name ( $columns ) {
	$columns['item_id'] = "アイテムID";
	unset($columns['date']);
	return $columns;
}
add_filter( 'manage_items_columns', 'add_column_name' );

//カスタムフィールドitem_idの項目に値を表示
function add_column_value ($column_name, $post_ID) {
	if( $column_name == 'item_id' ) {
		echo get_post_meta($post_ID, 'item_id', true);
	}
}
add_filter( 'manage_posts_custom_column', 'add_column_value', 10, 2 );

//カスタム投稿itemsの一覧を、カスタムフィールドitem_idの値順に並べ替え
function set_post_types_admin_order( $wp_query ) {
  if (is_admin()) {
	$post_type = $wp_query->query['post_type'];
	if ( $post_type == 'items' ) {
	  $wp_query->set('meta_key', 'item_id');
	  $wp_query->set('orderby', 'meta_value');
	  $wp_query->set('order', 'ASC');
	}
  }
}
add_filter( 'pre_get_posts', 'set_post_types_admin_order' );

[トラブル解決]カスタム投稿一覧で、値が表示されない

カスタム投稿一覧に、項目の追加はできたけれど、なぜか値が表示されない、というトラブルに悩まされました。

カスタム投稿やカスタムフィールドを管理するのに、Typesを使っていたのですが、他のプラグインを全部無効にしてみたり、別のカスタム投稿で試したりと苦闘の末、Types自身の、カスタム投稿の設定で、「階層」にチェックをつけていたことが原因のようでした。

Typesのカスタム投稿設定で「階層」にチェックがついていた

これは、カスタム投稿の hierarchical に該当する設定で、投稿そのものに親子関係をもたせられるようにする、というやつです。
仮にTypesを使わずにカスタム投稿をつくって試すと、hierarchical をtrueにしても問題ないので、Types固有の現象かもしれません。

いずれにしても、今回の事案では意味もなくチェックをつけてしまっていたようで、いらなのでチェックを外すと、すんなりと解決しました。

同じように、Types使ってて、カスタム投稿一覧にカスタムフィールドが表示されずに困ったら、設定を疑ってみてください。

それにしても、たったこれだけに、半日を費やしてしまいました。。。
TypesやAdvance Coutom Fields を使うと、カスタム投稿やカスタムフィールドの管理が楽な反面、トラブル発生時に手こずるというアルアルですね。

 

DataTableの重複する行を取得する

DataTableに属するDataRowの任意の列から、重複する行を除去する方法はあるのですが、

            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn("id", typeof(ulong));
            dt.Columns.Add(dc);
            dc = new DataColumn("name", typeof(string));
            dt.Columns.Add(dc);

            NewMethod(dt, 10000, "nakata");
            NewMethod(dt, 10001, "honda");
            NewMethod(dt, 10002, "kagawa");
            NewMethod(dt, 10002, "nagatomo");
            NewMethod(dt, 10003, "okazaki");

            DataView dv = new DataView(dt);
            DataTable dt2 = dv.ToTable(true, "id");//trueでDistinct(重複を取り除く)

削除ではなく、同じ値のものを取得いたくて、その方法を調べたのですが、

たとえば、DataTable.Margeを使ってRowStatusで取得する方法
https://social.msdn.microsoft.com/Forums/ja-JP/3e46f64d-fed3-4370-a16a-0987c8710050/datatable-linq?forum=vbgeneralja

とか、なるほど!というのもあったのですが、これはprimary keyが設定してあるDataTable同志でなければいけないので、そうでない場合はどうすればいいか。というわけですが、DataTable.Selectで取り出してチェックするしかなさそう。

たとえば、こんな感じで。

            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn("id", typeof(ulong));
            dt.Columns.Add(dc);
            dc = new DataColumn("name", typeof(string));
            dt.Columns.Add(dc);

            NewMethod(dt, 10000, "nakata");
            NewMethod(dt, 10001, "honda");
            NewMethod(dt, 10002, "kagawa");
            NewMethod(dt, 10002, "nagatomo");
            NewMethod(dt, 10003, "okazaki");

            DataView dv = new DataView(dt);
            DataTable dt_distinct = dv.ToTable(true, "id");//重複除去


            StringBuilder sb = new StringBuilder();
            foreach (DataRow _dr in dt_distinct.Rows)
            {
                string id = _dr["id"].ToString();
                if (id != "")
                {
                    if ((int)dt.Compute("COUNT(id)", "id=" + id) > 1)
                    {
                        sb.Append(((sb.Length > 0) ? " OR " : "") + "id=" + id);
                    }
                }
            }
            DataRow[] dr_array = dt.Select(sb.ToString());
            DataTable dt_overlap = dr_array.CopyToDataTable();

なんか、気持ち悪いですが、Selectで重複しているIDだけを取り出すという、ベタなやり方。

こんなときは、LINQでいきます。

            DataTable dt = new DataTable();
            DataColumn dc = new DataColumn("id", typeof(ulong));
            dt.Columns.Add(dc);
            dc = new DataColumn("name", typeof(string));
            dt.Columns.Add(dc);

            NewMethod(dt, 10000, "nakata");
            NewMethod(dt, 10001, "honda");
            NewMethod(dt, 10002, "kagawa");
            NewMethod(dt, 10002, "nagatomo");
            NewMethod(dt, 10003, "okazaki");

            var dr_array = from row in dt.AsEnumerable()
                            where (
                                from _row in dt.AsEnumerable() 
                                where (ulong)row["id"] == (ulong)_row["id"] 
                                select _row["id"]
                                ).Count() > 1 //重複していたら、2つ以上見つかる
                            select row;
            DataTable dt_overlap = dr_array.CopyToDataTable();

もっと、すっきりできそうだけど、こんな感じで。

全角/半角を押しても日本語入力できない

Dellのデスクトップパソコンで、英語版のWindows7をインストール後に、日本語の言語パックを入れて対応しているものの、キーボードが対応できていない、という事例があって、対応を依頼されました。

本来なら、
http://freesoft.tvbok.com/win10/tips/keyboard.html
http://www.sakyou.com/ManualShop/Windows/06_keyboard/02_106keyboard/17_Win7PRO/index.html
こちらを参考にすれば、解決する話。だったはずなのですが、Windwosの言語設定を修正したり、デバイスドライバーを再インストールしたり、レジストリを修正したりしても、一向に解決しませんでした。

で、ふとキーボードをつないでいるUSB端子の、さす場所を変えてみると、デバイスドライバをインストールし始めたのですが、ヒューマンインターフェイスデバイスのところにKB216...という感じのドライバが追加されていました。

ちなみに、DellのキーボードはKB216とシールに印字されていたので、そういうことなのかもしれません。

キーボードは、「標準 PS/2 101/102 キーボード」は追加されることなく、「HID標準キーボード」があるだけでも、全角/半角キーで切り替えができるようになりました。

結局、背面のもともとさしていたUSBコネクタとは違うところに差し込むことで、無事解決しました。

  1. windowsの言語設定を日本語キーボードにして、英語は削除
  2. レジストリを修正(KORを削除)
  3. USBコネクタの場所変える→デバイスドライバがインストールされる

で解決しました。

SSLで一部のひとから「警告が表示されるんですけど」

SSLのインストールがうまくいったと思ったら、一部の人で警告が表示されると。

ほとんどの人は問題ないのに、なぜ?

サイト側では、すべてのリンクをhttpsに変えてるし、原因はなんぞ?

ここでチェックしてもらうと、warningっていわれるし。
https://cryptoreport.geotrust.com/checker/views/certCheck.jsp

気になるのは、警告が表示される端末と、されない端末があるという。

これはいったいなんだ?と、いろいろ調べてると、ここに書いてありました。

http://www.ict-solutions.jp/rapidsslca.html

なるほど。中間証明書のインストールができてないと。

おはずかしー。

サクラインターネットでの、中間証明書のインストール方法はここに書いてあります。

https://help.sakura.ad.jp/hc/ja/articles/206054842--%E7%8B%AC%E8%87%AASSL-%E5%88%A9%E7%94%A8%E4%B8%AD%E3%81%AESSL%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%82%92%E6%9B%B4%E6%96%B0%E3%81%99%E3%82%8B%E6%89%8B%E9%A0%86

 

MySQL Incorrect string value: の解決策

MySQL である文字をInsertしようとしてエラーが発生。

Incorrect string value: '\xF0\xA6\x9A\xB0\xE7\x94...' for column 'name' at row 1

調べてみると、どうやら「サロゲートペア」である文字をInsertしようとしたからみたいでした。

結論からいうと、MySQL側のcharacter_set_serverをutf8mb4にすればいいようです。

my.iniの編集

my.iniの[mysqld]セクションにある

character_set_server=utf8

を、

character_set_server=utf8mb4

に変更します。(なければ追加)
変更できたらMySQLを再起動。
MySQLの再起動は、タスクマネージャーのサービスタブをクリックして、MySQLを探して右クリック→再起動(R) でできます。

1607170002

テーブルのキャラクターセットの変更

さらに、すでにあるテーブルのキャラクターセットを変更します。
次の例は、memberというテーブル名のキャラクターセットをutf8mb4に変更します。

 ALTER TABLE member CONVERT TO CHARACTER SET utf8mb4;


面倒ですけど、テーブル1つずつ変更しました。
一括して変更する方法もあるみたいですけど、変換に失敗することもあるので、確認しながらの方がいいと思います。

これで、Incorrect string value エラーは出なくなりました。

ちなみに、utf8mb4は、MySQL 5.5.3以降でなけらば使えないらしいので、しれより古いバージョンのMySQLを使っているのであれば、MySQL自身のバージョンアップが必要ってことになりますね。。。

JQuery リンクのHover時のデザインいろいろ

リンクタグの上にマウスを載せた時に、CSSだけではなく、JQueryでそれっぽくリンクを主張するいろいろ。

オンマウスで文字の色とリンクの背景を反転させる

色をanimateするには、JQueryUIが必要です。なので、HEADに以下を予め追加しておきます。

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>

これはリンクです。

jQuery(document).ready(function($){
    $("a span , .post a").on({
        "mouseenter": function(){
            //マウスオーバーで文字の色を白に。背景を赤に。
            $(this).stop().animate( { color:"#fff" , backgroundColor: "#f01d4f" }, 200);
        },
        "mouseleave": function(){
            //マウスオーバーで文字の色を白に。背景を赤に。
            $(this).stop().animate( { color:"#f01d4f" , backgroundColor: 'transparent' }, 200);
        }
    });
});

$("a span , .post a") としているのは、フロントページなどで特定のリンクだけに反映させたい部分には、aタグ内にspanで囲っておけばいいし、それ以外の投稿や固定ページでは、投稿者が意識しなくてもいいようにしたかったので。

マウスオーバーで薄くする

これはリンクです。

jQuery(document).ready(function($){
    $("a.fadeto").on({
        "mouseenter": function(){
            //マウスオーバーで透過率60%
            $(this).stop().fadeTo(100,0.6);
        },
        "mouseleave": function(){
            //マウスオーバーで透過率100%(透過なし)
            $(this).stop().fadeTo(100,1.0);
        }
    });
});

WordPressのダッシュボードにPHPバージョンを表示する

WordPressはPHPで動作していますが、そのバージョンによって、function.phpに書き込んだ内容が、エラーになったりならなかったりします。

なので、事前にPHPのバージョンを確認したいことがありますが、そんなときにはfunction.phpに以下を書き加えます。

function show_php_ver_dashboard_widget_function() {
    echo 'PHP version: ' . phpversion();
}

function show_php_ver_add_dashboard_widgets() {
    wp_add_dashboard_widget('show_php_ver_dashboard_widget', 'PHPのバージョン', 'show_php_ver_dashboard_widget_function');    
}
add_action('wp_dashboard_setup', 'show_php_ver_add_dashboard_widgets' );

ダッシュボードにPHPのバージョンが表示されるようになります。

echo 'PHP version: ' . phpversion();

の部分をいじれば、オリジナルのダッシュボードウィジェットが作れるっというわけでした。

C# DateTimePickerの値を非表示にする。

C#で、DateTimePickerをそのまま使うと、nullを入れられません。

なので、常に何かの値が入っているのですが、それは仕方がないとして、せめて非表示にしたい場合に次のようにします。

まず、フォームにDateTimePicker、dateTimePicker1を配置しているとします。
Form1にDateTimePickerを配置

DateTimePickerのvalueには、Nullが入らないので、代わりにDateTime? dateTime を値の入れ物として用意します。DateTime型もNull非許容型なので、?をつけてNull許容型にします。

dateTimePicker.Format の値を DateTimePickerFormat.Customにして、CustomFormat に半角の空白を入れると、日付が非表示になるので、これを利用します。

カレンダーで日付が設定されるなど数値が変更になったときには、イベントを発動して日付を表示させます。
そして、Deleteキーが押された時はdateTime変数をnullにして、DateTimePickerの数値を非表示にします。

DateTime? dateTime;

private void Form1_Load(object sender, EventArgs e)
{
 //イベントの追加
 this.dateTimePicker1.ValueChanged += new System.EventHandler(this.dateTimePicker1_ValueChanged);
 this.dateTimePicker1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dateTimePicker1_KeyDown);

 //今日の日付を設定した場合
 //dateTime = DateTime.Today;
 //setDateTimePicker(dateTime);

 //nullを設定した場合
 dateTime = null;
 setDateTimePicker(dateTime);
}

private void dateTimePicker1_KeyDown(object sender, KeyEventArgs e)
{
 if (e.KeyData == Keys.Delete)
 {
 //Deleteキーが押されたら、dateTimeにnullを設定してdateTimePicker1を非表示に
 dateTime = null;
 setDateTimePicker(dateTime);
 }
}

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
 //dateTimePicker1の値が変更されたら表示する
 dateTime = dateTimePicker1.Value;
 setDateTimePicker(dateTime);
}

private void setDateTimePicker(DateTime? datetime)
{
 if (datetime == null)
 {
 //DateTimePickerFormat.Custom にして、CostomFormatは半角の空白を入れておくと、日時が非表示になる。
 dateTimePicker1.Format = DateTimePickerFormat.Custom;
 dateTimePicker1.CustomFormat = " ";
 }
 else
 {
 //フォーマットを元に戻して、値をセットする。
 dateTimePicker1.Format = DateTimePickerFormat.Long;
 dateTimePicker1.Value = (DateTime)datetime;
 }
}

こんな感じで。ちゃんと日付が非表示になりますし、日付を設定すれば、表示されます。

日付が非表示になります。 日付を設定