プログラム初心者のcakephp2.x・wordpress情報

プログラム初心者のcakephp2.xの技術情報・wordpressやAPI関連も覚書(PHP・mySQL)

google MAP API v3でDB連帯などもろもろできるかやってみた。

今回やりたいと思っていることは、DBにある駅情報をgooglemap上に表示することで、まぁー半径5km以内のデータだけ表示して、地図をドラッグ&ズームサイズ変更により駅情報を表示させるようにすること。ついでにサイドバーに現在mapに表示している駅情報をリストで表示することを目標に作成しました!

 

■ 参考にしたページ

Creating a Store Locator with PHP, MySQL & Google Maps

ズーム範囲の固定

データベースから地図の中心座標より半径(km)を指定した距離範囲

 

最終的にはこのようになりました。

f:id:cakephp2002:20130305141514j:plain

 

ちょっと電車のアイコンが分かり図らい感じになっていますね。まー気にしないでくださいね。

 

まず最初にgoogleのページにあるサンプルが非常に分かりやすいので、それをカスタマイズしていきます。

 

個人的にズームの範囲を固定したかったため、参照サイトの記述をそのまま追加。ズーム範囲を指定しました。

function load() {

 ~ 途中省略~

    //google map のズーム機能制限用
	google.maps.event.addListenerOnce(map, "projection_changed", function(){
      map.setMapTypeId(google.maps.MapTypeId.HYBRID);  //一瞬だけマップタイプを変更
      setZoomLimit(map, google.maps.MapTypeId.ROADMAP);
      setZoomLimit(map, google.maps.MapTypeId.HYBRID);
      setZoomLimit(map, google.maps.MapTypeId.SATELLITE);
      setZoomLimit(map, google.maps.MapTypeId.TERRAIN);
      map.setMapTypeId(google.maps.MapTypeId.ROADMAP);  //もとに戻す
    });
}
//ズーム範囲を固定関数
  function setZoomLimit(map, mapTypeId){
    //マップタイプIDを管理するレジストリを取得
    var mapTypeRegistry = map.mapTypes;
    //レジストリから現在のマップタイプIDのMapTypeを取得する
    var mapType = mapTypeRegistry.get(mapTypeId);
    //ズームレベルを設定する
    mapType.maxZoom = 20;  //SATELLITE・HYBRIDは機能しない
    mapType.minZoom = 13;
}

 

次にeventによって処理を分けるようにしていきます。

googlemapにいろいろevent関数が用意されているので、その中から、ドラッグが終了したとき(dragend)とズームを変えたとき(zoom_changed)を利用します。

 

function load() {

 ~ 途中省略~
 
    //google mapのズームが変更したとき発生するイベント
	google.maps.event.addListener(map, 'zoom_changed', function()
	{
	var center = map.getCenter();
	searchLocationsNear(center); //searchLocationsNear()は中心座標を取得して、phpでDBからデータを取得する関数
	});
	//google mapのドラッグ画終了したとき発生するイベント
	google.maps.event.addListener(map, 'dragend', function()
	{
	var center = map.getCenter();
	searchLocationsNear(center); 
	});
}

 

 いよいよ最後にサイドメニューを追加します。

searchLocationsNear()の中で、DBから取得したデータの配列をsidemarkersへ。createMarkerButton(sidemarkers);で作成します。

 

function createMarkerButton(marker) {
  //サイドバーにマーカ一覧を作る
  var ul = document.getElementById("marker_list");
  var li = document.createElement("li");
  var title = marker.getTitle();
  var line_name = marker.get('line_name');
  li.innerHTML = '<a href="javascript:;">'+title+'('+line_name+')</a>';
  ul.appendChild(li);
  
  //サイドバーがクリックされたら、マーカーを擬似クリック
  google.maps.event.addDomListener(li, "click", function(){
    google.maps.event.trigger(marker, "click");
  });
}

 

コレでだいたいOK。event発生時にmapに表示するマーカーとサイドメニューをクリアにすれば完成です。

 

今回のソースの完全版がほしい方はコメント下さい!なんて・・・

googleの検索情報を考える。検索品質評価ガイドライン(google)など様々な情報

サイトを作成・運営する上で、googleの動向は見逃せない。なぜなら、サイトが生きるのも死ぬのもgoogle次第というほどに検索エンジンのひとり勝ち状態になっているから。

 

思わぬペナルティで、インデックスが削除されるとgoogleの検索結果に表示されずアクセスが激減してしまいます。SEOを意識しすぎるのはよくないけど、googleの動向には気をつけていたほうが安全でスムーズな運営が出来ると思います。

 

つい先日googleが新たに「検索のしくみ」についてのページを公開しました。


How Search Works

この情報の中には、検索エンジンがどのようにして、サイトをインデックスして検索者に情報を提供しているかがよくわかります。また、googleの考えるサイトの「検索品質評価ガイドライン(英語)」も一般公開されています。そのほかにも、スパム行為やペナルティを受けた場合の再審査情報などが載っているので、目を通しておくことをおすすめします。

 

もっと情報がほしい方は「検索サービスのヘルプ」「検索フォーラム(質疑応答が活発)」、ちょっと難しいけどアルゴリズムや考え方が垣間見れる「研究報告書 (英語)」などがあります。各レベルに合わせて、必要な情報をチェックして見てはどうでしょうか。

wordpressのカテゴリ&タクソノミーの一覧にテキスト&画像を追加してみた。

wordpressのカテゴリ&タクソノミーの一覧にテキスト&画像を追加してみた。

 

まず最初にこれらのリストページは複数ページにまたがっているため、最初のページのみに画像やテキストを表示することとする。

最初のページかどうかの条件分岐が必要

 

 条件分岐タグ is_paged() を使う。
if ( !is_paged() ) : // 1ページ目
else : // 2ページ目以降
endif;
wordpressの条件分岐参照

 

 つぎにカテゴリの設定項目にカスタムフィードを追加する。

function.phpに下記内容を追加します。(カテゴリの場合) 

add_action ( 'edit_category_form_fields', 'extra_category_fields');
function extra_category_fields( $tag ) {
    $t_id = $tag->term_id;
    $cat_meta = get_option( "cat_$t_id");
?>
<tr class="form-field">
    <th><label for="extra_text">説明テキスト</label></th>
	<td><input type="text" name="Cat_meta[extra_text]" id="extra_text" size="25" value="<?php if(isset ( $cat_meta['extra_text'])) echo esc_html($cat_meta['extra_text']) ?>" /></td>
</tr>
<tr class="form-field">
	<th><label for="upload_image">バナー画像URL</label></th>
	<td>
		<input id="upload_image" type="text" size="36" name="Cat_meta[img]" value="" /><br />
	</td>
</tr>
<?php
}

 

データを保存するために以下の処理も追加します。

コレもfunction.phpに追加します。

 

add_action ( 'edited_term', 'save_extra_category_fileds');
function save_extra_category_fileds( $term_id ) {
    if ( isset( $_POST['Cat_meta'] ) ) {
       $t_id = $term_id;
	   $cat_meta = get_option( "cat_$t_id");
	   $cat_keys = array_keys($_POST['Cat_meta']);
		  foreach ($cat_keys as $key){
		  if (isset($_POST['Cat_meta'][$key])){
			 $cat_meta[$key] = $_POST['Cat_meta'][$key];
		  }
	   }
	   update_option( "cat_$t_id", $cat_meta );
    }
}

 

タグの場合やタクスノミーの場合は 「add_action ( 'edit_category_form_fields', 'extra_category_fields');」と記述している部分を修正すれば利用可能。

コレもfunction.phpに追加します。

 

●タグの場合
add_action ( 'edit_tag_form_fields', 'extra_tag_fields');
●タクソノミーの場合
add_action ( '[タクソノミー名]_edit_form_fields', 'extra_taxonomy_fields');
※複数を連続して記述をしても問題なく動作します。extra_tag_fields、extra_taxonomy_fieldsを同一にすれば、同じ項目を利用できます。

 

最後に表示部分です.。カテゴリはcategory.php,タグはtag.phpもしくはachive.phpで表示させたい部分に以下を追加します。なお最初のページだけ表示させたいので、最初に書いた条件分岐「!is_paged() 」を全体に定義すれば完了です。

 

<ul class="clearfix">
<?php 
$tag_all = get_terms("category", "fields=all");//タクソノミーの場合はそのタクソノミー名
foreach($tag_all as $value):
$cat_data = get_option('cat_'.intval($value--->term_id));
?>
<li>
<?php echo esc_html($value->name) ?>
<img src="" width="110" height="110" />
<?php echo esc_html($cat_data['extra_text']) ?><br />
</li>
<?php endforeach; ?>
</ul> 

 

cakePHP2.xでこの機能あるのかな?ちょっとざっと調べてみた。(RSS・PubSubHubbubって?)

RSSフィードの生成については標準機能で出来るようで、情報が多かった。
コレはすんなり出来そうだ。

 

まずRSSの拡張子を利用できるようにroutes.phpに1行追加する

Router::parseExtensions('rss');

RSSを配信したいコントローラーにRequestHandlerコンポーネントを追加
すでにコンポーネントを設定している場合は配列に「RequestHandler」を追加すればOK

public $components = array('RequestHandler');

RSSを配信したいコントローラー(仮にpost)に配信用のアクション(仮にfeed)を追加作成

app/Controller/PostsController.php
public function feed() {
    $this->Post->recursive = -1;
    $this->set('posts', $this->Post->find('all', array('limit'=>10, 'order'=>'Post.created desc')));
}

そしてviewの作成

app/View/Posts/rss/feed.ctp
$channel = array (
    'title' =--> 'サイトの名前',
    'link' => 'http://サイトURL/',
    'guid' => 'http://サイトURL/',
    'description' => 'フィードの説明',
    'rss_url' => 'フィードのURL'
); $this->set('channel',$channel); echo $this->Rss->items($posts, 'transformRSS'); function transformRSS($posts) { return array( 'title' => $posts['Post']['name'], //投稿のタイトル 'link' => array('action' => 'view', $posts['Post']['id']), //投稿ページへのリンク先 'guid' => array('action' => 'view', $posts['Post']['id']), //投稿ページへのリンク先 'description' => $posts['Post']['body'], //投稿の本文 'pubDate' => $posts['Post']['created'] //投稿日時 ); }

RSSの確認は「http://サイトURL/posts/feed.rss」にアクセスすると確認できます。
\app\View\Layoutsに設定したレアウトのheadに以下を追加すれば終了。

<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://サイトURL/posts/feed.rss" />

次が大変PubSubHubbubの実装・・・。結局決策の情報はなかった。

仕方なくRSSのdefault.ctpに必要な記述はべた書きで対応。もっとスマートな方法があったらぜひ修正したい。

 

app/View/Layouts/defaulr.ctp
if (!isset($channel)) {
    $channel = array();
}
if (!isset($channel['title'])) {
	$channel['title'] = $title_for_layout;
}

$this->Rss->document(
	$this->Rss->channel(
		array(), $channel, $this->fetch('content')
	)
);
echo '<?xml version="1.0" encoding="UTF-8">
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>'.$channel['title'].'</title>
<atom:link href="'.$channel['feedURL'].'" rel="self" type="application/rss+xml">
<link>'.$channel['link'].'</link>
<description>'.$channel['description'].'</description>
<language>ja</language>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com">
<atom:link rel="hub" href="http://superfeedr.com/hubbub">';
print_r($this->fetch('content'));
echo '</channel></rss>';

あとはレアウト.ctpに記述の追加(RSS 2.0の記述のしたあたりに追加)

<link rel="hub" href="http://pubsubhubbub.appspot.com/" />
<link rel="hub" href="http://superfeedr.com/hubbub" />

初歩的なミスに愕然とした。日本語の扱いって難しい・・・。

ファイルのアップロードで日本語の場合

※ファイルは所定のディレクトリにアップロードできていた。

 

DBに格納した場合に文字化けしてしまう。

1、プログラム上でのファイル名のエンコーディング(mb_convert_encoding)。

2、DBのカラムの文字コードが一致しない。

 

今回のケースでは2のDBの指定カラムがまったくちがうエンコードだったので、文字化けを引きおこしていたのだった。

 

う・・・情けない。

日本語って文字化けに引っかかりやすいから思わぬ時間を取られてしまいますね。