ホーム > タグ > カスタマイズ

カスタマイズ

【EC-CUBE】初回の買い物は、ポイント●倍にする

EC-CUBEを再びカスタマイズ。
初回の買い物は、ポイント●倍にして、その倍率は、管理画面のパラメータ設定で変えられるようにする。

その1)初回の買い物かどうか、判定してポイントを●倍にするロジックを追加。

/data/class/SC_CartSession.phpの function getAllProductsPoint() に下記コードを追加。
L206あたり。

$id = $_SESSION[$this->key][$i]['id'][0];
$point = SC_Utils_Ex::sfPrePoint($price, $point_rate, POINT_RULE, $id);
$total+= ($point * $quantity);
}
$objQuery = new SC_Query();
$objCustomer = new SC_Customer();
//customer_idを検証
$customer_id = $objCustomer->getValue(“customer_id”);
$order_count = $objQuery->count(“dtb_order”, “customer_id= ? and del_flg = 0″, array($customer_id));
if ($order_count == 0) {
$total = $total*FIRST_POINT;
}
return $total;
}

// カートへの商品追加

その2)管理画面のパラメータ設定にポイント倍率設定用の項目を増やす。

DBの、mtb_constantsを開いて、カラムを1行追加。

id FIRST_POINT
name 1
rank 523※一番最後に追加
remarks 初回購入ポイント倍率

nameの値が倍率になる。デフォルトは”1″(倍)。

倍率を変更するときは、管理画面のパラメータ設定で値を変えればOK。

その他の注意点としては、キャンセルがあったときなどにポイントの手動付け替えなど、色々懸念することが出てきてしまうので、

  • ポイント付与のタイミングを発送済みか支払い確認済みなどのステータスになったとき、などに変更しておいたほうがいい
  • 注文のキャンセルがあったときは、自動でポイントが付け替えられるほうがいい

こういうことも一緒にカスタマイズしておいたほうがいい。この辺は、次のバージョンあたりで解消されそうな気もするけども。

WORDPRESSで登録メール等が届かない・・・対応

WORDPRESSでは、新しいユーザーが登録された場合やお問い合わせフォームプラグインなどの設置で、自動的にメールが届く仕組みがある。

・・・はずなのだが、このメールが一向に届かない。

原因は、inetd。

およそのサーバにですね、inetd(※inetd は、FTP、POP3、telnet といったインターネットサービスが使うポート番号を(指定されて)監視する。監視対象のポートにTCPパケットあるいはUDPパケットが届くと、inetd は対応するサーバプログラムを起動し、コネクションを制御させる。by wikipedia)というのが、走っているわけなんですが、このinetdが、メール送信の時に、from情報もしているようで、WORDPRESSのデフォルトのまま設定ではこの監視に引っかかってしまうので、メールを受け取れない。

どういうことかというと。

WORDPRESSは、通知メールの送信に、wordpress@あなたのサイト名のアドレスでメールを送信します。このメールアドレスが、サーバ内に実在していれば、問題がないのだが、実在していないメールアドレスからの送信は、inetdの監視に引っかかってしまう。

て、おいおい。。。

最初からwordpress@domainなんてメアド誰がつくっとるねん;
とかツッコんでしまう。

よって、主な対応方法は、2つかと。。。

  1. 上記、wordpress@domainというメアドを実際に作ってWPの管理アドレスに設定する。
  2. または、このメアドをサーバに実在している実際の運用アドレスに変更する。

ま、たいてい、2ですな。

やり方。

/wp-includes/pluggable.php を開いて、L354あたりの、

$from_email = ‘wordpress@’ . $sitename;

を、(1)

$from_email = ‘あなたのめあど@domain‘;

か(2)

$from_email = ‘あなたのめあど@‘. $sitename;

に変更。

ただし、(2)の方法で変更する場合、wordpressで送信されるメールアドレスは、wwwのサブドメインは削除されることに留意すること。(→つまり、ドメインが、www.domain.comでも@から後ろは、domain.comにしかなりませんよ、でも、sub.domain.comだったら、そのままですよ、ということです。まあ、これは普通メアド作るときにも同じようなルールになるので、問題ないかと思うのですが・・・)

こういうところって結構悩みますね。

ちなみに、メアドチェックは、サーバー内で掛かりますよ。他のサービスで持ってるメアドで運用しようとしている場合は、要注意です。

【EC-CUBE】詳細ページに商品への問い合わせボタンを追加する

  1. 商品の詳細ページに、商品についての問い合わせボタンを追加し、問い合わせフォームへ遷移させる。
  2. 問い合わせフォームには、商品詳細ページから飛んできた問い合わせについては、フォームに商品名や品番などを自動入力されるように変更する。

フォーラムを見て、こんなことをやってみました。(ryoさん、ありがとうございます)

まず、/data/Smarty/templates/defaults/detail.tpl 内の、問い合わせボタンを追加したい位置に、問い合わせボタン用のフォームを追加する。(そのとき、注文用のフォームとかぶったり、入れ子にならないように注意!)

<form method=”post” action=”<!–{$smarty.const.SITE_URL}–>contact/”>
<input type=”hidden” name=”products_name” value=”<!–{$arrProduct.name|escape}–>” />
<input type=”submit” name=”" value=”この商品について問い合わせる” />
</form>

※ SSLに飛ばすなら赤字を「$smarty.const.SSL_URL」に変更。

つぎに、/data/Smarty/templates/contact/index.tpl のL67あたり、お問い合わせ内容を記入してもらうtextareaに下記コードを追加。

<tr>
<th>お問い合わせ内容<span class=”attention”>※</span><br />
<span class=”mini”>(全角<!–{$smarty.const.MLTEXT_LEN}–>字以下)</span></th>
<td><span class=”attention”><!–{$arrErr.contents}–></span>
<textarea name=”contents” class=”area380″ cols=”60″ rows=”20″ style=”<!–{$arrErr.contents|sfGetErrorColor}–>”><!–{if $smarty.post.products_name != ” }–><!–{$smarty.post.products_name|escape}–>に関するお問い合わせ

<!–{/if}–>
<!–{$contents|escape}–></textarea></td>
</tr>

<!–{if $smarty.post.products_name != ” }–><!–{/if}–>
を記載することによって、「(商品名)に関するお問い合わせ」という部分が、商品ページからの遷移の場合のみ追加されることになる。(=通常のお問い合わせの場合入らない)

【EC-CUBE】最近チェックした商品の履歴を○○件表示させる

商品の詳細ページと一覧ページで最近チェックした商品の履歴を表示させる。

  1. 履歴はクッキーで(1ヶ月)保持する
  2. 最新の閲覧商品を(4件)表示させ、重複する閲覧履歴は表示しない
  3. 表示テンプレートはブロックで生成し、一覧ページにも詳細ページにも共通して使えるようにする

その1)表示用ブロックを作成する。

管理画面から新規ブロックを作成し、下記コードを保存。
(下記はオススメ商品ブロックに倣った2列表示のテンプレートコード。商品名、価格、説明適宜修正する。)

<!–▼閲覧履歴ここから–>
<!–{if $arrItemHistory}–>
<div id=”whoboughtarea” class=”clearFix”>
<h2><img src=”<!–{$TPL_DIR}–>img/products/title_history.jpg” width=”580″ height=”30″ alt=”閲覧履歴” /></h2>
<div class=”whoboughtblock”>
<!–{section name=cnt loop=$arrItemHistory}–>
<!–{if ($smarty.section.cnt.index % 2) == 0}–>
<!–{if $arrItemHistory[cnt].product_id}–>
<!– 左列 –>
<div class=”whoboughtleft”>
<!–{if $arrItemHistory[cnt].main_list_image != “”}–>
<!–{assign var=image_path value=”`$arrItemHistory[cnt].main_list_image`”}–>
<!–{else}–>
<!–{assign var=image_path value=”`$smarty.const.NO_IMAGE_DIR`”}–>
<!–{/if}–>
<a href=”<!–{$smarty.const.DETAIL_P_HTML}–><!–{$arrItemHistory[cnt].product_id}–>”>
<img src=”<!–{$smarty.const.SITE_URL}–>resize_image.php?image=<!–{$image_path|sfRmDupSlash}–>&width=65&height=65″ alt=”<!–{$arrItemHistory[cnt].name|escape}–>” />
</a>

<!–{assign var=price02_min value=`$arrItemHistory[cnt].price02_min`}–>
<!–{assign var=price02_max value=`$arrItemHistory[cnt].price02_max`}–>
<h3><a href=”<!–{$smarty.const.DETAIL_P_HTML}–><!–{$arrItemHistory[cnt].product_id}–>”><!–{$arrItemHistory[cnt].name|escape}–></a></h3>

<p>価格<span class=”mini”>(税込)</span>:<span class=”price”>
<!–{if $price02_min == $price02_max}–>
<!–{$price02_min|sfPreTax:$arrSiteInfo.tax:$arrSiteInfo.tax_rule|number_format}–>
<!–{else}–>
<!–{$price02_min|sfPreTax:$arrSiteInfo.tax:$arrSiteInfo.tax_rule|number_format}–>~<!–{$price02_max|sfPreTax:$arrSiteInfo.tax:$arrSiteInfo.tax_rule|number_format}–>
<!–{/if}–>円</span></p>
<p class=”mini”><!–{$arrItemHistory[cnt].main_list_comment|escape|nl2br}–></p>
</div>
<!– /左列 –>
<!–{/if}–>
<!–{/if}–>

<!–{if ($smarty.section.cnt.index % 2) != 0}–>
<!–{* assign var=nextCnt value=$smarty.section.cnt.index+1 *}–>
<!–{if $arrItemHistory[cnt].product_id}–>
<!– 右列 –>
<div class=”whoboughtright”>
<a href=”<!–{$smarty.const.DETAIL_P_HTML}–><!–{$arrItemHistory[cnt].product_id}–>”>
<!–{if $arrItemHistory[cnt].main_list_image != “”}–>
<!–{assign var=image_path value=”`$arrItemHistory[cnt].main_list_image`”}–>
<!–{else}–>
<!–{assign var=image_path value=”`$smarty.const.NO_IMAGE_DIR`”}–>
<!–{/if}–>
<img src=”<!–{$smarty.const.SITE_URL}–>resize_image.php?image=<!–{$image_path|sfRmDupSlash}–>&width=65&height=65″ alt=”<!–{$arrItemHistory[cnt].name|escape}–>” />
</a>
<!–{assign var=price02_min value=`$arrItemHistory[cnt].price02_min`}–>
<!–{assign var=price02_max value=`$arrItemHistory[cnt].price02_max`}–>
<h3><a href=”<!–{$smarty.const.DETAIL_P_HTML}–><!–{$arrItemHistory[cnt].product_id}–>”><!–{$arrItemHistory[cnt].name|escape}–></a></h3>

<p>価格<span class=”mini”>(税込)</span>:<span class=”price”>

<!–{if $price02_min == $price02_max}–>
<!–{$price02_min|sfPreTax:$arrSiteInfo.tax:$arrSiteInfo.tax_rule|number_format}–>
<!–{else}–>
<!–{$price02_min|sfPreTax:$arrSiteInfo.tax:$arrSiteInfo.tax_rule|number_format}–>~<!–{$price02_max|sfPreTax:$arrSiteInfo.tax:$arrSiteInfo.tax_rule|number_format}–>
<!–{/if}–>円</span></p>
<p class=”mini”><!–{$arrItemHistory[cnt].main_list_comment|escape|nl2br}–></p>
</div>
<!– /右列 –>
<!–{/if}–>
<!–{/if}–>
<!–{/section}–>
</div>
</div>
<!–{/if}–>

その2)詳細ページ用のphpに、コードを2箇所追加する。

/data/class/paes/products/LC_Page_Products_Detail.php

L100あたり、

// レイアウトデザインを取得
$helper = new SC_Helper_PageLayout_Ex();
$helper->sfGetPageLayout($this, false, “products/detail.php”);

// パラメータ管理クラス
$this->objFormParam = new SC_FormParam();
// パラメータ情報の初期化
$this->lfInitParam();
// POST値の取得
$this->objFormParam->setParam($_POST);

// ファイル管理クラス
$this->objUpFile = new SC_UploadFile(IMAGE_TEMP_DIR, IMAGE_SAVE_DIR);
// ファイル情報の初期化
$this->lfInitFile();

// 商品閲覧履歴取得
$this->Get_ItemHistory();

// 管理ページからの確認の場合は、非公開の商品も表示する。
if(isset($_GET['admin']) && $_GET['admin'] == ‘on’) {
SC_Utils_Ex::sfIsSuccess(new SC_Session());
$status = true;
$where = “del_flg = 0″;
} else {
$status = false;
$where = “del_flg = 0 AND status = 1″;
}

そして、コードの一番最後のほう、 function lfConvertParam()の後ろにも追加。

function lfConvertParam() {
if (!isset($this->arrForm['quantity']['value'])) $this->arrForm['quantity']['value'] = “”;
$value = $this->arrForm['quantity']['value'];
$this->arrForm['quantity']['value'] = htmlspecialchars($value, ENT_QUOTES, CHAR_CODE);
}
//商品詳細閲覧履歴取得、表示データ取得処理
function Get_ItemHistory() {
$cnt = 0;
// ページを再読み込み後に表示
if (isset($_COOKIE['product'])) {
foreach ($_COOKIE['product'] as $name => $value) {
$objQuery = new SC_Query();
// DBから一覧表示用商品情報取得
$arrRet = $objQuery->select(“*”, “vw_products_allclass AS alldtl”, “product_id =”.$value);
$this->arrItemHistory[$cnt] = $arrRet[0];
$cnt = $cnt+1;
}
}

//クッキーに重複項目がないか判定処理
$duplicateFlg = true;
if (isset($_COOKIE['product'])) {
foreach ($_COOKIE['product'] as $name => $value) {
if($value == $_GET['product_id']){
$duplicateFlg = false;
}
}
}

//重複がない場合クッキーに設定
if($duplicateFlg){
if($cnt < 4){
$cnt = $cnt + 1;
setcookie(“product[".$cnt."]“, $_GET['product_id'],time()+60*60*24*30 );
}else{
$reNum = 1;
foreach ($_COOKIE['product'] as $name => $value) {
if($reNum > 1){
$setNum = $reNum -1;
setcookie(“product[".$setNum."]“, $value, time()+60*60*24*30 );
}
$reNum = $reNum + 1;
}
setcookie(“product[4]“, $_GET['product_id'], time()+60*60*24*30 );
}
}
}
}
?>

その3)一覧ページ用phpにも同様にコードを追加する。

/data/class/paes/products/LC_Page_Products_list.php

L82あたり、

// レイアウトデザインを取得
$helper = new SC_Helper_PageLayout_Ex();
$helper->sfGetPageLayout($this, false, DEF_LAYOUT);

//2008.04.11 商品閲覧履歴取得
$this->Get_ItemHistory();

// 管理ページからの確認の場合は、非公開の商品も表示する。
if(isset($_GET['admin']) && $_GET['admin'] == ‘on’) {
SC_Utils_Ex::sfIsSuccess(new SC_Session());
$status = true;
$where = “del_flg = 0″;
} else {
$status = false;
$where = “del_flg = 0 AND status = 1″;
}

//表示件数の選択
if(isset($_POST['disp_number'])
&& SC_Utils_Ex::sfIsInt($_POST['disp_number'])) {
$this->disp_number = $_POST['disp_number'];
} else {

コードの最後のほう、

function lfconvertParam () {
foreach ($this->arrForm as $key => $value) {
if (preg_match(‘/^quantity[0-9]+/’, $key)) {
$this->arrForm[$key]
= htmlspecialchars($this->arrForm[$key], ENT_QUOTES, CHAR_CODE);
}
}
}
//2008.04.11 商品詳細閲覧履歴取得、表示データ取得処理
function Get_ItemHistory() {
$cnt = 0;
// ページを再読み込み後に表示
if (isset($_COOKIE['product'])) {
foreach ($_COOKIE['product'] as $name => $value) {
$objQuery = new SC_Query();
// DBから一覧表示用商品情報取得
$arrRet = $objQuery->select(“*”, “vw_products_allclass AS alldtl”, “product_id =”.$value);
$this->arrItemHistory[$cnt] = $arrRet[0];
$cnt = $cnt+1;
}
}

//クッキーに重複項目がないか判定処理
$duplicateFlg = true;
foreach ($_COOKIE['product'] as $name => $value) {
if($value == $_GET['product_id']){
$duplicateFlg = false;
}
}

//重複がない場合クッキーに設定
if($duplicateFlg){
if($cnt < 4){
$cnt = $cnt + 1;
setcookie(“product[".$cnt."]“, $_GET['product_id'],time()+60*60*24*30 );
}else{
$reNum = 1;
foreach ($_COOKIE['product'] as $name => $value) {
if($reNum > 1){
$setNum = $reNum -1;
setcookie(“product[".$setNum."]“, $value, time()+60*60*24*30 );
}
$reNum = $reNum + 1;
}
setcookie(“product[4]“, $_GET['product_id'], time()+60*60*24*30 );
}
}
}
}
?>

を追加。

その4)最後に、管理画面から、先に作っていた表示用ブロックを詳細ページまたは一覧ページのレイアウトに追加。

【EC-CUBE】MySQL使用の場合のページ表示スピードを改善する。

EC-CUBEのmySQL用のSQLクエリーは、どうも表示速度にとっても問題を及ぼすようだ。。。

基本、PSQLメインの仕様だから、とか言われるのだけど、実際には、DBはMSQLしかないサーバーも多いし、色々運用のことも考えると、やっぱりMSQLでもそれなりのパフォーマンスはして欲しい・・・と思っているのは私だけではないはず。(^^;
いいシステムなのに、ところどころオシイんですよね。でも、最近ちょっと活発になってきてよくなってくる予感。

先日来フォーラムで、MSQLのパフォーマンスについて色々見ていたところ、あるスレッドで、

/data/class/db/dbfactory/SC_DB_DBFactory_MYSQL.php の商品データ呼び出しクエリーを変更すれば、パフォーマンスに劇的に変化がある、という話を目にし、早速やってみる。結果、PSQLのDBを使用した場合とほとんど遜色ないくらい速くなった!

要は簡単で、コミュニティ版で提供されているファイルに、SC_DB_DBFactory_MYSQL.phpを置き換えて、dtb_productsなどのDBテーブルをカスタマイズして携帯用のコメントなどを追加している場合は、そのカラムについてのSQLの値を追加すればいいだけ。(これは、カスタマイズしている場合だけね。)
ソース中のクエリーの中で、データベースにカスタマイズしてカラムを追加してある場合、dtb_productsに「comment7」を追加しているのであれば、comment6の行の下に同じ記述ルールでに、comment7を取得する記述を1行追加してあげるだけでいい。例えば、comment7の追加が必要な場所は、mein_comment(商品の詳細説明)が呼び出されている箇所(現在のソースなら下記2箇所)と同じところになるので、ソース内を検索してみるべし。

以下は、コミュニティ版で提供されているSC_DB_DBFactory_MYSQL.phpのソース(2/20現在)。多分、EC-CUBEのダウンロードサイトから最新の物を持ってきたほうがいいと思うし、そのうち正式版でも同じように改善されると思うけど、一応コピペしておく。

// {{{ requires
require_once(CLASS_PATH . “db/SC_DB_DBFactory.php”);

/**
* MySQL 固有の処理をするクラス.
*
* このクラスを直接インスタンス化しないこと.
* 必ず SC_DB_DBFactory クラスを経由してインスタンス化する.
* また, SC_DB_DBFactory クラスの関数を必ずオーバーライドしている必要がある.
*
* @package DB
* @author LOCKON CO.,LTD.
* @version $Id:SC_DB_DBFactory_MYSQL.php 15267 2007-08-09 12:31:52Z nanasess $
*/
class SC_DB_DBFactory_MYSQL extends SC_DB_DBFactory {

/**
* DBのバージョンを取得する.
*
* @param string $dsn データソース名
* @return string データベースのバージョン
*/
function sfGetDBVersion($dsn = “”) {
$objQuery = new SC_Query($this->getDSN($dsn), true, true);
list($db_type) = split(“:”, $dsn);
$val = $objQuery->getOne(“select version()”);
return “MySQL ” . $val;
}

/**
* MySQL 用の SQL 文に変更する.
*
* @access private
* @param string $sql SQL 文
* @return string MySQL 用に置換した SQL 文
*/
function sfChangeMySQL($sql){
// 改行、タブを1スペースに変換
$sql = preg_replace(“/[\r\n\t]/”,” “,$sql);
// view表をインラインビューに変換する
$sql = $this->sfChangeView($sql);
// ILIKE検索をLIKE検索に変換する
$sql = $this->sfChangeILIKE($sql);
// RANDOM()をRAND()に変換する
$sql = $this->sfChangeRANDOM($sql);
// TRUNCをTRUNCATEに変換する
$sql = $this->sfChangeTrunc($sql);
return $sql;
}

/**
* 文字コード情報を取得する
*
* @return array 文字コード情報
*/
function getCharSet() {
$objQuery = new SC_Query();
$arrRet = $objQuery->getAll(“SHOW VARIABLES LIKE ‘char%’”);
return $arrRet;
}

/**
* テーブルの存在チェックを行う SQL 文を返す.
*
* @return string テーブルの存在チェックを行う SQL 文
*/
function getTableExistsSql() {
return “SHOW TABLE STATUS LIKE ?”;
}

/**
* インデックスの検索結果を配列で返す.
*
* @param string $index_name インデックス名
* @param string $table_name テーブル名
* @return array インデックスの検索結果の配列
*/
function getTableIndex($index_name, $table_name = “”) {
$objQuery = new SC_Query(“”, true, true);
return $objQuery->getAll(“SHOW INDEX FROM ” . $table_name . ” WHERE Key_name = ?”,
array($index_name));
}

/**
* インデックスを作成する.
*
* @param string $index_name インデックス名
* @param string $table_name テーブル名
* @param string $col_name カラム名
* @param integer $length 作成するインデックスのバイト長
* @return void
*/
function createTableIndex($index_name, $table_name, $col_name, $length = 0) {
$objQuery = new SC_Query($dsn, true, true);
$objQuery->query(“CREATE INDEX ? ON ? (?(?))”, array($index_name, $table_name, $col_name, $length));
}

/**
* テーブルのカラム一覧を取得する.
*
* @param string $table_name テーブル名
* @return array テーブルのカラム一覧の配列
*/
function sfGetColumnList($table_name) {
$objQuery = new SC_Query();
$sql = “SHOW COLUMNS FROM ” . $table_name;
$arrColList = $objQuery->getAll($sql);
$arrColList = SC_Utils_Ex::sfswaparray($arrColList);
return $arrColList["Field"];
}

/**
* テーブルを検索する.
*
* 引数に部分一致するテーブル名を配列で返す.
*
* @param string $expression 検索文字列
* @return array テーブル名の配列
*/
function findTableNames($expression = “”) {
$objQuery = new SC_Query();
$sql = “SHOW TABLES LIKE ?”;
$arrColList = $objQuery->getAll($sql, array(“%” . $expression . “%”));
$arrColList = SC_Utils_Ex::sfswaparray($arrColList, false);
return $arrColList[0];
}

/**
* View の WHERE 句を置換する.
*
* @param string $target 置換対象の文字列
* @param string $where 置換する文字列
* @param array $arrval WHERE 句の要素の配列
* @param string $option SQL 文の追加文字列
* @return string 置換後の SQL 文
*/
function sfViewWhere($target, $where = “”, $arrval = array(), $option = “”){

$arrWhere = split(“[?]“, $where);
$where_tmp = ” WHERE ” . $arrWhere[0];
for($i = 1; $i < count($arrWhere); $i++){
$where_tmp .= SC_Utils_Ex::sfQuoteSmart($arrval[$i - 1]) . $arrWhere[$i];
}
$arrWhere = $this->getWhereConverter();
$arrWhere[$target] = $where_tmp . ” ” . $option;
return $arrWhere[$target];
}

/**
* View をインラインビューに変換する.
*
* @access private
* @param string $sql SQL 文
* @return string インラインビューに変換した SQL 文
*/
function sfChangeView($sql){

$arrViewTmp = $this->viewToSubQuery();

// viewのwhereを変換
foreach($arrViewTmp as $key => $val){
$arrViewTmp[$key] = strtr($arrViewTmp[$key], $this->getWhereConverter());
}

// viewを変換
$changesql = strtr($sql, $arrViewTmp);

return $changesql;
}

/**
* ILIKE句 を LIKE句へ変換する.
*
* @access private
* @param string $sql SQL文
* @return string 変換後の SQL 文
*/
function sfChangeILIKE($sql){
$changesql = eregi_replace(“(ILIKE )”, “LIKE “, $sql);
return $changesql;
}

/**
* RANDOM() を RAND() に変換する.
*
* @access private
* @param string $sql SQL文
* @return string 変換後の SQL 文
*/
function sfChangeRANDOM($sql){
$changesql = eregi_replace(“( RANDOM)”, ” RAND”, $sql);
return $changesql;
}

/**
* TRUNC() を TRUNCATE() に変換する.
*
* @access private
* @param string $sql SQL文
* @return string 変換後の SQL 文
*/
function sfChangeTrunc($sql){
$changesql = eregi_replace(“( TRUNC)”, ” TRUNCATE”, $sql);
return $changesql;
}

/**
* WHERE 句置換用の配列を返す.
*
* @access private
* @return array WHERE 句置換用の配列
*/
function getWhereConverter() {
return array(
“&&crscls_where&&” => “”,
“&&crsprdcls_where&&” =>”",
“&&noncls_where&&” => “”,
“&&allcls_where&&” => “”,
“&&allclsdtl_where&&” => “”,
“&&prdcls_where&&” => “”,
“&&catcnt_where&&” => “”
);
}

/**
* View をサブクエリに変換するための配列を返す.
*
* @access private
* @return array View をサブクエリに変換するための配列
*/
function viewToSubQuery() {
$sql['vw_products_allclass_detail'] =<<< __EOS__
(
SELECT
dtb_products.product_id,
dtb_products.name,
dtb_products.deliv_fee,
dtb_products.sale_limit,
dtb_products.sale_unlimited,
dtb_products.maker_id,
dtb_products.rank,
dtb_products.status,
dtb_products.product_flag,
dtb_products.point_rate,
dtb_products.comment1,
dtb_products.comment2,
dtb_products.comment3,
dtb_products.comment4,
dtb_products.comment5,
dtb_products.comment6, //例えば、携帯用コメントとして、dtb_productsに「comment7」を追加しているのであれば、この下の行に、「dtb_products.comment7,」と1行追加してあげる。
dtb_products.note,
dtb_products.file1,
dtb_products.file2,
dtb_products.file3,
dtb_products.file4,
dtb_products.file5,
dtb_products.file6,
dtb_products.main_list_comment,
dtb_products.main_list_image,
dtb_products.main_comment,
dtb_products.main_image,
dtb_products.main_large_image,
dtb_products.sub_title1,
dtb_products.sub_comment1,
dtb_products.sub_image1,
dtb_products.sub_large_image1,
dtb_products.sub_title2,
dtb_products.sub_comment2,
dtb_products.sub_image2,
dtb_products.sub_large_image2,
dtb_products.sub_title3,
dtb_products.sub_comment3,
dtb_products.sub_image3,
dtb_products.sub_large_image3,
dtb_products.sub_title4,
dtb_products.sub_comment4,
dtb_products.sub_image4,
dtb_products.sub_large_image4,
dtb_products.sub_title5,
dtb_products.sub_comment5,
dtb_products.sub_image5,
dtb_products.sub_large_image5,
dtb_products.sub_title6,
dtb_products.sub_comment6,
dtb_products.sub_image6,
dtb_products.sub_large_image6,
dtb_products.del_flg,
dtb_products.creator_id,
dtb_products.create_date,
dtb_products.update_date,
dtb_products.deliv_date_id,
T4.product_code_min,
T4.product_code_max,
T4.price01_min,
T4.price01_max,
T4.price02_min,
T4.price02_max,
T4.stock_min,
T4.stock_max,
T4.stock_unlimited_min,
T4.stock_unlimited_max,
T4.class_count
FROM
dtb_products
LEFT JOIN
(
SELECT
product_id,
MIN(product_code) AS product_code_min,
MAX(product_code) AS product_code_max,
MIN(price01) AS price01_min,
MAX(price01) AS price01_max,
MIN(price02) AS price02_min,
MAX(price02) AS price02_max,
MIN(stock) AS stock_min,
MAX(stock) AS stock_max,
MIN(stock_unlimited) AS stock_unlimited_min,
MAX(stock_unlimited) AS stock_unlimited_max,
COUNT(*) as class_count
FROM dtb_products_class
GROUP BY product_id
) AS T4
ON dtb_products.product_id = T4.product_id
)
__EOS__;

return array(
“vw_cross_class” => ‘
(SELECT T1.class_id AS class_id1, T2.class_id AS class_id2, T1.classcategory_id AS classcategory_id1, T2.classcategory_id AS classcategory_id2, T1.name AS name1, T2.name AS name2, T1.rank AS rank1, T2.rank AS rank2
FROM dtb_classcategory AS T1, dtb_classcategory AS T2 ) ‘,

“vw_cross_products_class” =>’
(SELECT T1.class_id1, T1.class_id2, T1.classcategory_id1, T1.classcategory_id2, T2.product_id,
T1.name1, T1.name2, T2.product_code, T2.stock, T2.price01, T2.price02, T1.rank1, T1.rank2
FROM (SELECT T1.class_id AS class_id1, T2.class_id AS class_id2, T1.classcategory_id AS classcategory_id1, T2.classcategory_id AS classcategory_id2, T1.name AS name1, T2.name AS name2, T1.rank AS rank1, T2.rank AS rank2
FROM dtb_classcategory AS T1, dtb_classcategory AS T2 ) AS T1 LEFT JOIN dtb_products_class AS T2
ON T1.classcategory_id1 = T2.classcategory_id1 AND T1.classcategory_id2 = T2.classcategory_id2) ‘,

“vw_products_nonclass” => ‘
(SELECT
T1.product_id,
T1.name,
T1.deliv_fee,
T1.sale_limit,
T1.sale_unlimited,
T1.category_id,
T1.rank,
T1.status,
T1.product_flag,
T1.point_rate,
T1.comment1,
T1.comment2,
T1.comment3,
T1.comment4,
T1.comment5,
T1.comment6, //例えば、携帯用コメントとして、dtb_productsに「comment7」を追加しているのであれば、この下の行に、「T1.comment7,」と1行追加してあげる。
T1.file1,
T1.file2,
T1.file3,
T1.file4,
T1.file5,
T1.file6,
T1.main_list_comment,
T1.main_list_image,
T1.main_comment,
T1.main_image,
T1.main_large_image,
T1.sub_title1,
T1.sub_comment1,
T1.sub_image1,
T1.sub_large_image1,
T1.sub_title2,
T1.sub_comment2,
T1.sub_image2,
T1.sub_large_image2,
T1.sub_title3,
T1.sub_comment3,
T1.sub_image3,
T1.sub_large_image3,
T1.sub_title4,
T1.sub_comment4,
T1.sub_image4,
T1.sub_large_image4,
T1.sub_title5,
T1.sub_comment5,
T1.sub_image5,
T1.sub_large_image5,
T1.sub_title6,
T1.sub_comment6,
T1.sub_image6,
T1.sub_large_image6,
T1.del_flg,
T1.creator_id,
T1.create_date,
T1.update_date,
T1.deliv_date_id,
T2.product_id_sub,
T2.product_code,
T2.price01,
T2.price02,
T2.stock,
T2.stock_unlimited,
T2.classcategory_id1,
T2.classcategory_id2
FROM (SELECT * FROM dtb_products &&noncls_where&&) AS T1 LEFT JOIN
(SELECT
product_id AS product_id_sub,
product_code,
price01,
price02,
stock,
stock_unlimited,
classcategory_id1,
classcategory_id2
FROM dtb_products_class WHERE classcategory_id1 = 0 AND classcategory_id2 = 0)
AS T2
ON T1.product_id = T2.product_id_sub) ‘,

“vw_products_allclass” => ”
(
SELECT
alldtl.*,
dtb_category.rank AS category_rank,
T2.category_id,
T2.rank AS product_rank
FROM
{$sql['vw_products_allclass_detail']} AS alldtl
LEFT JOIN
dtb_product_categories AS T2
ON alldtl.product_id = T2.product_id
LEFT JOIN
dtb_category
ON T2.category_id = dtb_category.category_id
) “,

“vw_products_allclass_detail” => $sql['vw_products_allclass_detail'],

“vw_product_class” => ‘
(SELECT * FROM
(SELECT T3.product_class_id, T3.product_id AS product_id_sub, classcategory_id1, classcategory_id2,
T3.rank AS rank1, T4.rank AS rank2, T3.class_id AS class_id1, T4.class_id AS class_id2,
stock, price01, price02, stock_unlimited, product_code
FROM ( SELECT
T1.product_class_id,
T1.product_id,
classcategory_id1,
classcategory_id2,
T2.rank,
T2.class_id,
stock,
price01,
price02,
stock_unlimited,
product_code
FROM (dtb_products_class AS T1 LEFT JOIN dtb_classcategory AS T2
ON T1.classcategory_id1 = T2.classcategory_id))
AS T3 LEFT JOIN dtb_classcategory AS T4
ON T3.classcategory_id2 = T4.classcategory_id) AS T5 LEFT JOIN dtb_products AS T6
ON product_id_sub = T6.product_id) ‘,

“vw_category_count” => ‘
(SELECT T1.category_id, T1.category_name, T1.parent_category_id, T1.level, T1.rank, T2.product_count
FROM dtb_category AS T1 LEFT JOIN dtb_category_total_count AS T2
ON T1.category_id = T2.category_id) ‘
);
}
}
?>

ポスグレへ移行テストもしているけど、正直これだけ改善されたら、まあ、いいかな、MSQLのままでも、と思い始めている。。。

【EC-CUBE】mySQLからpostgreSQLへデータを移行する

パフォーマンス改善のため、MSQLからPSQLへのデータベース移行を行う。

移行前 mySQL5.2 → 移行後 postgreSQL8.3 (※VER末番省略)

PSQLの8.3系はパフォーマンスは高いが、SQLの互換性で色々と問題が出ることもあるようなので、モジュールなどを使用する際は、注意すること。

移行の場合は、一旦同サーバ内に、サブドメインなどで別環境を作っておき、そちらでインストールしてから本番環境からDBを切り替えるのが望ましい。

【主な手順】

  1. MYSQLのDBからphpMyAdminで、テーブルごとにCSVデータを書き出す。
  2. (一応同じサーバ内に別環境をつくり)EC-CUBEをポスグレ使用でインストール
  3. postgreSQL(以下PSQL)のDBのテーブル内のデータを全て空にする
  4. テーブルごとに、先にMSQLからダウンロードしていたCSVデータをインポート(※携帯用コメントとショップ用コメントをカスタマイズ追加しているから、この際にPSQLのdtb_productsにcomment7とshop_comment1カラムを追加しておく。)
  5. ビューを調整。
    ・vw_product_class
    ・vw_products_allclass
    ・vw_products_allclass_detail
    ・vw_products_nonclass
    の4つのビューに、カスタマイズで追加していたコメントカラム(comment7、shop_comment1 ※ショップカラムは、表示しないので、allクラスとnonclassだけでもいいと思う)をそれぞれ追加して生成しなおす

では詳しい手順。

その1)

phpMyAdminを開いて、左のサイドメニューからテーブルを1つずつ選択。エクスポートタブメニューをクリックし、テーブルのエクスポートメニューで、

エクスポート:「MS Excel用CSVデータ」を選択。
Excelオプション:NULL/最初の1行目にフィールド名を追加する(チェックあり)/Excelの種類(Windows)
ファイルで保存する(チェック)/圧縮(無し)/エンコード(non)

で実行。

supremecenter53com-_-papalabs_ageha-_-dtb_baseinfo-_-phpmyadmin-264-pl2

エンコードの変換有無は、移行する相互のDBの文字エンコードが違う場合、文字化けを防ぐために必要になるが、書き出してからテキストエディタなどで様子を見ながら変換したほうが安心な気がする。

結構な数のテーブルがあるので、PSQLにインポートの際間違えないようにファイル名に気をつけながら順番に繰り返す。

その2)

PSQLでEC-CUBEインストール用のDBを1つ新規作成し、そこへ、もとのMSQLのEC-CUBEと同じバージョンのEC-CUBEを新規インストールする。

以前のものと同じバージョンにあわせるのは、DBの安全移行のため。ただしテーブル構造などが変わっていないバージョンの変更であれば、新しいEC-CUBEでもかまわない。
別のEC-CUBEを使う場合は、DBだけでなくファイルの移行も色々気をつけないといけないから正直めんどい;問題も切り分けにくいのでまずは、普通に移行だけ先に行ったほうがいいように思う。

その3)

ここで一旦新しいEC-CUBEの基本動作確認がベター。サーバー側の別のエラーが出ている場合は修正しておくこと。問題なければ、PSQLの各テーブルのデータを一旦空にする。

phpPgAdminを開いて、左メニューから、スキーマ→public→テーブルをクリックして選択。テーブルの一覧がでるので、ページ下の方の「複数行の操作」メニューから、「すべて選択する」—>「空にする」を選んで実行ボタンをクリック。

phppgadminjpg

これで、テーブルの構造は残るが値は消えた。

その4)

dtb_baseinfoを選択して、上のタブメニューからインポートを選ぶ。

フォーマット(CSV)/NULL文字を許可する(\n、NULL、殻の文字列・項目いずれもチェック)

先に保存していたMSQLのdtb_baseinfoのテーブルデータを選択して、インポートボタンをクリック。

phppgadmin2

これを、最後のテーブルまで繰り返す。

途中、インポートエラーが出たらメッセージごとにもとのMSQLデータを調整するなどして対応。カスタマイズして増やしたカラムに相当するカラムがPSQLのテーブルにない場合、エラーが出るので、その際は、該当するカラムをテーブルに追加しておく。(例えば、dtb_productsにcomment7などを追加していた場合、PSQLのインポートでは、そのデータを入れるカラムがまだないので、作成しておかなくてはいけない)

その5)

PSQLでは、VIEWを使用してテーブルから値をあらかじめ集めておくことで表示のパフォーマンスをあげている。上記のようなカスタマイズでMSQLのテーブルにカラムを追加していた場合、そのデータをEC-CUBEで表示させるならVIEWにも修正が必要になる。(例えば、上記携帯用コメントcomment7は、携帯ページで表示させるので、それを読み込んでいるVIEWにもデータがなくては表示エラーになってしまう)

今回は、

  • comment7→携帯ページ用商品説明文を入力&表示させている。
  • shop_comment1→商品登録時に店舗のメモを格納しているが管理画面で確認するだけでフロント表示はしない。

となっているので、

  • vw_product_class
  • vw_products_allclass
  • vw_products_allclass_detail
  • vw_products_nonclass

の4つのビューに、それぞれ、値を足すことにする。

  1. vw_product_classは、マスター的な役割をするので、comment7もshop_comment1も追加する
  2. vw_products_allclassには、comment7のみ追加
  3. vw_products_allclass_detailには、comment7のみ追加
  4. vw_products_nonclassには、もshop_comment1も追加する

vw_product_class以外には、shop_comment1のほうが必要かどうかちょいとあいまい。なくてもいいかもしれない。(エラー出たときに足せば・・・)

やり方。まず、左メニューからビューのvw_product_classを選択。ページの右上のほうのタブメニューからエクスポートを選択。
まずは、ダウンロードを選んで、一旦ローカルにビューのデータをバックアップ。その後、表示でファイルを開く。L18あたりの、 t6.comment6,の後ろに、 t6.comment7, t6.shop_comment1,を追加。ソースをドラッグ&コピー。

phpPgAdminへ戻り、左メニューのビューをクリックして、表示されるビューの一覧から、vw_product_classのテーブル内の「破棄」ボタンをクリックして、vw_product_classビューを破棄する。

画面の上の方のデータベース名をクリック。
SQLタブをクリックして、フォームに修正後のソースを貼り付けて、実行。

phppgadmin4

これで、新しく修正されたビューが再生成される。「レコードが見つかりません」と表示されればok。残りのビューについても同様に繰り返す。

vw_products_allclassは、t5.comment3, の後ろにt5.comment7,を、t1.comment3, の後ろにt1.comment7,を追加。

vw_products_allclass_detailは、t3.comment3, の後ろにt3.comment7, を追加。

vw_products_nonclassは、 t1.comment6, の後ろに、t1.comment7, t1.shop_comment1, を追加。

これでOK。

最終テストを行うので、新EC-CUBEから、/data/install.php以外のデータを一旦削除し、本番のec-cubeのソースをこちらにコピーしてくる。これで、本番の環境と同じプログラムでDBのみPSQLの環境ができたことになるので、データが正しく移行されて、表示されているか確認。

動作に問題がなければ、本番のec-cubeの/data/install.phpの接続データベースをPSQLの情報に変更して、接続するDBを入れ替えて完了。テストの段階で、PHPソースなどを変更しなければならなかった場合は、本番にもそれらを反映する。

以上。書いてると長いけど、慎重にやれば、作業自体はそれほど難しくはない。

保護中: WORDPRESS MUで特定ブログのカテゴリーの新着記事●件を表示させるコード

この投稿はパスワードで保護されています。表示するにはパスワードを入力してください:


【EC-CUBE】注文確認メールで支払い先口座情報を追加する

受注確認メールの支払い先をメール中に挿入する。その時に支払方法ごとに挿入内容を変える。

/data/Smarty/templates/default/mail_templates/order_mail.tplに、支払方法ごとに支払方法を追加する。

<!–{if $arrOrder.payment_method == “銀行振込” }–>
銀行振込み先:○○銀行 ○○支店
       口座番号 普通 ○○○○○
       口座名義 ○○○○

<!–{elseif $arrOrder.payment_method == “郵便振替” }–>
郵便振替え先:記号○○ 番号○○
       口座名義 ○○○○

<!–{else$arrOrder.payment_method == “○○ }–>
支払い先:○○
    
<!–{else}–>
代金引換えにて配送いたします。
商品お受取りの際、配達員に代金をお支払いください。

<!–{/if}–>

【EC-CUBE】PCサイトで追加した新着商品ブロックを携帯サイトでも追加する

以前に、追加した大変便利なブロック機能。「新着商品をブロックで表示する」(http://www.bton.net46.net/?p=493

 これは実装時には基本PCサイトでのみ動作していたのだけど、携帯でも同じように使用したい。

ということで、ちょこっと改変して、携帯でも使うことにする。

そこで、私は、http://www.bton.net46.net/?p=735で商品登録に携帯用のコメントを追加したので、モバイルサイトでは、PC用の普通の説明文ではなく、携帯用の説明文を表示させることにする。(そうすると絵文字も自由に使えるからね!)

さて、新着商品の表示だけど、トップページで、左に小さな写真、右に商品名、携帯用説明文(最初の60字)を表示させて、写真と商品名には詳細ページへのリンクをつける、ということにしたい。

その1)ブロックのPHPを作成する。

以前に作成した、/html/frontparts/bloc/new.phpをコピーして、/html/mobile/frontparts/bloc/new.phpとして保存。

コピーしたファイルを開き、最後から2行目、3行目の、

$objPage->init();
$objPage->process();

$objPage->mobileInit();
$objPage->mobileProcess();

に変更して保存。

その2)ブロック作成。

/data/Smarty/templates/default/mobile/frontparts/bloc/にnew.tplを作成し、下記ソースを参考に表示用のテンプレートブロックを作成する。

<!–{if count($arrFlagProducts) > 0}–>
<div style=”background-color:#3cf; color:#fff; font-size:small; padding:1px; text-align:center;”>新着商品</div>
<div style=”font-size:x-small; background-color:#cff;”>
<!–{section name=cnt loop=$arrFlagProducts step=1 max=6}–>
<!–{if $arrFlagProducts[cnt].main_list_image != “”}–>
<!–{assign var=image_path value=”`$arrFlagProducts[cnt].main_list_image`”}–>
<!–{else}–>
<!–{assign var=image_path value=”`$smarty.const.NO_IMAGE_DIR`”}–>
<!–{/if}–>
<div style=”clear:both;”><a href=”<!–{$smarty.const.MOBILE_DETAIL_P_HTML}–><!–{$arrFlagProducts[cnt].product_id}–>”><img src=”<!–{$smarty.const.SITE_URL}–>resize_image.php?image=<!–{$image_path|sfRmDupSlash}–>&amp;width=60&amp;height=60″ alt=”<!–{$arrFlagProducts[cnt].name|escape}–>” style=”float:left;margin-top:3px; margin-right:3px; margin-bottom:8px; margin-left:3px;” align=”left” border=”0″ /></a>
<span style=”<!–color:#f36;–>”>[emoji:148]&nbsp;<a href=”<!–{$smarty.const.MOBILE_DETAIL_P_HTML}–><!–{$arrFlagProducts[cnt].product_id}–>”><strong><!–{$arrFlagProducts[cnt].name|escape}–></strong></a></span><br /><br />
[emoji:76]<span style=”color:#666;”><!–{if !$arrProduct.comment7}–><!–{$arrFlagProducts[cnt].main_list_comment|mb_strimwidth:0:60:”…”|escape|nl2br}–><!–{else}–><!–{$arrFlagProducts[cnt].comment7|mb_strimwidth:0:60:”…”|escape|nl2br}–><!–{/if}–></span><br clear=”all” /></div>
<!–{/section}–>
</div>

ポイント。

リサイズイメージで、商品画像を60×60pxに変換している。
SECTIONのループで、max=6と指定しているので、新着商品は6個表示される。
imgタグのSTYLE属性で画像を左にfloatさせている。ドコモXHTMLでは、floatの解除は、brタグではできないので、divタグのスタイル属性でstyle=”clear:both;”とするんであるが、古い携帯の場合、これでクリアされないかもしれないので、念のため、保険代わりに<br clear=”all” />も追加しておく。
最後のほうで、携帯用のコメント(comment7)があれば、それを表示し、携帯コメントが登録されていなければ、PC用のコメントを表示する、としている。また、コメントはいずれも全角30字とし、それ以上長いものは、省略させている。
こんなとこ。
変数名が前回保存したPC用のソースで指定したものと一致しているか確認すること。(変数名が違うと表示されない)

その3)データベースから抽出されるデータにcommnet7を追加しておく。

/data/class/db/dbfactory/SC_DB_DBFactory_MYSQL.php

のL368あたりから(ver.2.3.3の場合)vw_products_allclassというのがあるので、この中の           comment3,の下あたりにcomment7,を1行追加。

ついでなので、その20行ほど下の、

 T0.comment3,の下にも、
 T0.comment7,を1行追加しておいた。

【EC-CUBE】携帯サイトのニュース表示を調整する

モバイルサイトでは、ニュースは、最新1つだけ、しかもタイトルのみしか表示されない。

これだと更新履歴や商品入荷情報などを配信したい場合、ちょいと不都合。

ということで、モバイルサイトのニュースでも、

日付: 「2009.02.01」 というように。
タイトル:「○○が入荷しました!」というように。
本文:「オススメの人気ブランド○○のTシャツ緊急入荷!急げ!」というように。(また、本文は、文字数を頭から20字のみ表示、というように丸めたい場合もあると思うので、それも踏まえて改修。)

こういう表記になるように変更する。

これも基本、PCサイトのソースを持ってきて変更するだけ。

NEWSはPCと同じCLASSのロジックを使用しているので、基本テンプレのファイルを修正するだけでOK。
PCサイトのほうからソースをコピーしてきて、モバイル用に表示のHTMLを変更していく。

ニュースブロックの中身を変更する。

/data/Smarty/templates/default/mobaile/frontparts/bloc/news.tpl

を開く。

ソースを下記を参考に変更する。(※XHTMLで記述している)

<div style=”color:#666; font-size:small;”><strong>NEWS!!</strong></div>
<!–{section name=data loop=$arrNews}–>
<!–{assign var=”date_array” value=”-”|explode:$arrNews[data].news_date_disp}–>
<div style=”color:#666; font-size:x-small;”>[emoji:e54]<!–{$date_array[0]}–>.<!–{$date_array[1]}–>.<!–{$date_array[2]}–></div>
<div style=”color:#666; font-size:x-small;”>
<!–{if $arrNews[data].news_url}–><a href=”<!–{$arrNews[data].news_url}–>”>
<!–{/if}–>
<!–{$arrNews[data].news_title|escape|nl2br}–>
<!–{if $arrNews[data].news_url}–></a></span>
<!–{/if}–><br />
<!–{$arrNews[data].news_comment|mb_strimwidth:0:40:”…”|escape|nl2br}–>
</div>
<!–{/section}–>

小さくポイントになるところを解説。

  1. SECTIONでloopさせている$arrNewsは、ニュースの数だけ繰り返し、という意味なので、例えば最新の3つのニュースを表示するのであれば、$arrNewsではなく、「3」といれる。
  2. <!–{$date_array[0]}–>.<!–{$date_array[1]}–>.<!–{$date_array[2]}–>は、2009.02.01というように日付の区切りを[.]にしているので、/にしたければ、[/]に変更すればよいし、[]、[]、[]としたければ、そのように記述。
  3. mb_strimwidth:0:40:”…”| この部分で、ニュース本文の最初(0文字目)から40字目(半角なので、全角文字の場合は、これで20字ということ)までを表示し、最後に[...]を追加する、ということを言っている。[...]を[続く]としたり、他の記号にすることもできるし、40字ではなく60字などにすることもできる。

 こんなもんかな?

【EC-CUBE】携帯サイトの検索でもカテゴリ一覧検索を使用したい

EC-CUBEでは携帯サイトの商品検索は、PCよりしょぼい・・・(失礼!)

というか、こういう仕様になったのにはそれなりの訳もあるのかもしれない(表示のパフォーマンスや色々あるのかもしれないし、単にこっちはとりあえず実装だったのかもしれない)が、PCサイトでは、商品検索でカテゴリ検索ができる。検索窓でカテゴリの一覧から検索対象のカテゴリを選択することができるのだ。

これが、モバイルのほうでは、いきなり検索したい商品名を入力してちょ、とくる。そして別画面で検索のみ行う仕様である。
初めてのユーザーや特定の商品名、キーワードのイメージがないユーザーには、ちょいと使いにくい仕様である。なので、これをカスタマイズして、PCと同じくカテゴリ検索ができるようにする。

searchimage

こういう感じ。この機能をブロックにして、トップページなどで利用できるようにする。
モバイルサイトでは、ブロックは管理画面から配置するのではなく、該当するテンプレート中に、直接インクルードするので、今回はデータベースと管理画面は触らない。

基本的には、PCサイトのsearchのロジックをMOBILEに移植するだけでOK。

【携帯サイトへカテゴリ検索ブロックの追加】

その1)ブロック用PHP作成。

/html/frontparts/bloc/search_products.php をコピーして、
/html/mobile/frontparts/bloc/search_products.php として保存。

コピーしたファイルを開き、最後から2行目、3行目に、

$objPage->init();
$objPage->process();

というそーすがあるのを、

$objPage->mobileInit();
$objPage->mobileProcess();

と変更する。

その2)ブロック作成。

/data/Smarty/templates/default/mobile/frontparts/bloc/に、SearchProducts.tplという名称でテンプレファイルを作成し、PC用のSearchProducts.tplを参考にしながら、コーディング。

参考までに、上記のようなデザインにするためのコードは下記。(※XHTMLにてコーディングした場合)

<div style=”background-color:#96c; color:#fff; font-size:small; padding:1px; text-align:center;”>[emoji:119]&nbsp;商品検索&nbsp;[emoji:119]</div>
<div style=”font-size:x-small; padding:1px; background-color:#EEE6F7;”>&nbsp;お探しの商品名・型番を入力してください。</div>
<div style=”text-align:center; font-size:x-small;”><br /><form name=”search_form” id=”search_form” method=”get” action=”<!–{$smarty.const.URL_DIR}–>products/list.php”>
カテゴリから選ぶ<br />
<input type=”hidden” name=”mode” value=”search” />
<select name=”category_id”>
<option label=”全ての商品” value=”">全ての商品</option>
<!–{html_options options=$arrCatList selected=$category_id}–>
</select><br />
商品名を入力する<br />
<input type=”text” name=”name2″ maxlength=”50″ value=”<!–{$smarty.get.name|escape}–>” />
<br />
<input type=”submit” name=”search” value=”&nbsp;&nbsp;&nbsp;検索&nbsp;&nbsp;&nbsp;”>
</form>

これで、検索ブロックの基本は完成。

その3)最後に、トップページへ検索ブロックを埋め込む。

/data/Smarty/templates/default/mobile/top.tpl の、検索窓を表示したい箇所に、

<!–{include_php file=`$smarty.const.MOBILE_HTML_PATH`frontparts/bloc/search_products.php}–>

と記述。もちろん他のページでもかまわない。現状のEC-CUBEの構造で、検索ページの中身をカテゴリ検索の形に変更したいのであれば、

/html/mobile/products/search.php と

/data/Smarty/templates/default/mobile/products/search.tpl のソースを上記で出来上がるソースに置き換えればいい。(または、別に上記ソースを作成しておいて、商品検索のリンクのみ、/html/mobile/frontparts/bloc/search_products.phpへのリンクパスに変更すればいい。

他にも色々やった(オススメや新着のランダム表示ブロックに携帯機能を追加したりとかトップエページにカテゴリリストをボーダーデザインで出すようにしたりとか)けど、以外にスムーズに行き過ぎ、小さく色々さわりすぎたもんで、手順を記録できず、整理するのが大変・・・(^^;

次のときに必要だから、思い出して必ず記録する!乙!

【EC-CUBE】携帯サイトをXHTML仕様にする

今はモバイルサイトの仕様過渡期なので、ちょいと注意が必要なんだけども。

というのも、少し前に、モバイルXHTMLの標準化について、なんとなく関係各処でオーソライズされたらしいので。けれど、しばらくは、色々な事情からこのネタも生きることであろう。

モバイルサイトをXHTMLにすると何がいいかというと、ドコモでインラインCSSが使えるようになる。
ドコモなどで、文字に背景をつけたいとかインラインスタイルを書いて色々ちょいと調整したいとか、ただでさえ制限の多い携帯のコーディングで、少しでも自由な表現をするには、やっぱりスタイルシートが使えないと不便。

画像の多様で容量上げて凝ったデザインにするのはECではつらいので、モバゲーみたいに色々デザインされたページを無理なくコードで実現しようとすると、やっぱりCSSが必要なんである。

細かいところは、携帯サイトのコーディングについて詳しいサイトがいくつも公開されているので、そちらにお願いすることにして、とりあえず抑えておくポイントは、EC-CUBEのようなシステムベースだから3キャリア共通でHTMLソースを使用したいという場合には、XHTMLで、ドコモ向けにコーディングし、小さなところで、auやソフトバンク向けに調整する、ということが必要なんである。

ドコモでは、XHTMLは、docタイプが適切に出力されて、MIMEタイプがapplication/xhtml+xmlとして認識されて、などいくつかの制限がクリアされないとXHTMLと認識されず、HTMLと認識されてしまう。

EC-CUBEはSMARTYのテンプレートを使用しているので、ページがdisplayされる前に、mimetypeにxhtml+xmlをセットする。

【EC-CUBEの携帯サイトを3キャリア対応のXHTMLにするための手順】

1)/data/Smarty/templates/default/mobile/site_frame.tplのヘッダを、

<?xml version=”1.0″ encoding=”Shift_JIS”?> ※この行はなくても可。
<!DOCTYPE html PUBLIC “-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/1.1)1.0//EN” “i-xhtml_4ja_10.dtd”>
<html xml:lang=”ja”> 

または、

<?xml version=”1.0″ encoding=”Shift_JIS”?> ※この行はなくても可。
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
“http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml” lang=”ja” xml:lang=”ja”>
<head>
<meta http-equiv=”Content-Type” content=”application/xhtml+xml; charset=Shift_JIS” />

とする。

2)/data/class/helper/SC_Helper_Mobile.phpのL253あたりに、

 function sfMobileInit() {
ini_set(“default_mimetype”, “application/xhtml+xml”);  //1行追加
$this->lfMobileInitInput();

これで、OK。

【EC-CUBE】携帯サイトで、画像リサイズの問題を解決する

その1)

デザイン画像について。

EC-CUBEでは、携帯サイトに使用している画像は、容量圧縮のため、自動的に低解像度のJPGに変換され、アクセスごとにアクセスしてきた携帯端末の画面サイズに合わせてリサイズされ、/upoad/mobile_image/にたまっていく。

けれど、これをされると、最初から携帯サイト向けに最適化したデザイン画像まで全てJPGで圧縮されるため、画質がエラきたない;しかも、小さなサイズの画像も横幅が一旦画面いっぱいになるようにサイズ変更される。(なんで、GIFで容量も最適化してアップロードした携帯用画像までJPG変換するのか・・・)

これでは、どの端末で見ても携帯画面の横幅いっぱいに画像が表示されますよ、奥さん。以上の弊害が大きすぎるので、もう少しグレードアップして、本当にキレイに最適化されるまで、暫定的にこの自動リサイズ機能は使わないことにする。

auやドコモでは、横幅いっぱいにしたい画像は、横幅が大きければ端末のほうで自動的にリサイズして表示してくれるので、240px位で作っておけばいいのだ。

/data/require_base.php

のL72あたり(EC-CUBE Ver.2.3.3の場合)、

require_once(CLASS_PATH . “SC_MobileImage.php”);

をコメントアウト。

これで勝手にリサイズ&変換されなくなる。

ただし、これで、横幅自動変換機能はあくまで携帯端末の機能に頼ることになるので、ソフトバンクの高解像度携帯など、一部の携帯では、横幅が広いのに小さくしか画像が表示されず、レイアウトがちょいと見にくいなど、弊害もなくはないということは認識しておく必要アリ。

その2)

つぎに、商品画像について。

商品画像は、管理画面の商品登録で、大・中・小の3種類の大きさで保存される。(必須登録は中サイズで、中または大画像をアップロードすると、それより小さいサイズは登録時に自動的にリサイズされた画像が作成される)

これは、どのサイズもPCサイトではそれなりの大きさ及び画質で表示させたいので、携帯用に小さい画像にしてしまうのは、ちぃとな~。

ところが、携帯では、なぜかresize_imageが使用できない。。。

このままでは、携帯ページのコーディングで画像サイズを指定して小さく見せることはできるが、商品リストに画像も表示したいときなんかは、画像自体は元の容量だから、容量制限のキビシイ携帯サイトでは、やっぱりつらいのである。

ということで、require.phpを少し修正して、携帯サイトでも、resize_imageが使用できるようにする。これで容量エコになる♪

携帯サイトでresize_imageがうまく動作しないのは、リダイレクトが影響しているらしい。

/html/require.php のコード、一番下のほうに、

header(“Location: “. SC_Utils_Ex::sfRmDupSlash($url . $path));
exit;

というソースがあるので、これを、

/* resize_image.phpのときだけ、リダイレクト解除 */
if(!preg_match(“/resize_image.php/i”, $path)) {
header(“Location: “. SC_Utils_Ex::sfRmDupSlash($url . $path));
exit;
}

と変更。

表示させるほうのHTMLは、

<img src=”<!–{$smarty.const.SITE_URL}–>resize_image.php?image=<!–{$image_path|sfRmDupSlash}–>&amp;width=60&amp;height=60″>

などとすればOK。

参考サイト:http://xoops.ec-cube.net/modules/newbb/viewtopic.php?viewmode=flat&topic_id=1838&forum=11

【EC-CUBE】メール送信者を社名から店舗名に変更する

EC-CUBEでは、なぜか、お問い合わせの確認メールなどを配信するときに送信元が、基本情報の店名ではなく、社名になっている。

ので、これを店名に変更。

LC_Page_Admin_Mail_Sendmail.phpのL135あたり、

,$objSite->data["company_name"]             // 送信元名

,$objSite->data["shop_name"]             // 送信元名

と変更。これで、ショップ名でメールが配信される。

【EC-CUBE】トラブル回避のためのインストールTIPS

2月20日一部追記・編集しました。——————–

EC-CUBEをインストールすると、結構なトラブルに見舞われる(^^;
ざっと思いついただけでも、

  • DBの文字化け
  • 携帯サイトで購入フローエラー
  • 郵便番号住所データ登録でエラー
  • DBのタイムゾーン問題(海外サーバなどでシステム時計のタイムゾーンが日本の標準とあってない場合など)
  • HTACCESSとPHP.INIの設定

すでに対応策をメモったものがほとんどだけど、サーバーによって対応策は違うし、順不同に個別のものをメモっただけなので、一度整理して、クリーンインストールを前提にインストール方法としてまとめようと思う。

DBがpostgreSQLの場合は、EC-CUBEは比較的トラブルも少ないようなので&今のところB豚はポスグレでインストールすることがほぼ無いので、DBは取り合えずmySQL想定で。

【EC-CUBEのインストール】

1)まずは事前確認。インストールするサーバーの環境を確認しておく。

  1. PHPとmySQLのバージョンは5以上がベター。EC-CUBEの公式対応バージョンは、
    分類 ソフトウェア 動作確認済み
    OS Windows Windows 2000 ProfessionalWindows 2000 ServerWindows 2003 ServerWindowsXP ProfessionalWindowsNT Workstation 4.0WindowsNT Server 4.0
    UNIX Linux glibc 2.1/2.2/2.3
    FreeBSD 5.4以降
    言語 PHP PHP4.1.x以降
    PHP5.0.x以降
    ライブラリ 画像生成 freetype2 2.1.x以降
    gd 2.0.x以降
    データベース Postgres PostgreSQL 7.4.x以降
    MySQL MySQL4.1以上
    (MySQL5.x系を含む)

    となっているが、1系の開発&サポートが打ち切られることもあって、今後の運用を考えるとPHP、mySQLは、どちらもver.5以上にしておいたほうが無難。

  2. サーバーのPHPがapacheのモジュール版であるかCGI版であるかを確認しておく。また、HTACCESSやPHP.INIでのサーバー設定のオーバーライドができるかどうかも確認。注意点は、(特にHTACCESSで)php_valueとphp_flagの上書き設定ができるかどうかが重要な確認事項。
    EC-CUBEの各種設定を行う際に、サーバーのデフォルト設定を個別に上書きして使用しないといけないことが多い。特に携帯サイトも一緒に使用したい場合は、これが正しく設定できないと動作がおかしくなる原因になりやすい。
    EC-CUBEでは、サーバーのphp初期設定を、HTACCESSまたはカスタムのphp.iniファイルで上書き変更している。まずPCサイト用に設定変更を行って、さらに携帯サイトのみ、さらに設定を携帯用に上書きしている。(PCの文字エンコードがUTF-8で携帯がSHIFT_JISであるため。)
    その際、PHPがCGI版で動作しているのであれば、HTACCESSファイルでは、PHPの設定の上書きはできないため、ユーザーが自分のカスタムPHP.INIファイルでそれぞれ設定を行うことになり、PHPがAPACHEモジュールで動作している場合は、HTACCESSファイルでPHP設定を上書きすることになる。
    ここでさらに1つ留意点は、PHPがapache版でHTACCESSでphp初期設定の上書きを行う場合は、ユーザーはルートのディレクトリとmobileのメインディレクトリにそれぞれ設定事項を書いたHTACCESSファイルを1つずつ配置すればいいが、PHPがCGI版でphp.iniで設定を行う場合は、EC-CUBEの/html/ディレクトリ以下の、phpファイルがあるすべてのディレクトリにそれぞれ、php.iniファイルを置いていいかなければならない。これは結構面倒。もう1つ、さらにphp.iniがユーザーごとにメインディレクトリに1つしか設定できないサーバーがある。これは、つまり=EC-CUBEでは、携帯サイトのディレクトリで別のphp.ini設定が利用できないということなので、携帯サイトも運用したいのであれば、そういうサーバーは利用しないほうがいいと思う。
    扱いやすいのは、apache版PHPのサーバーでHTACCESSファイルでの設定。ただし、PHP自体の動作はCGI版のほうが速いとか・・・海外では、CGI版がほとんどですね。。。
    また、URLをSEO対策して静的HTML化するカスタマイズを行いたいのであれば、HTACCESSでMOD_REWRITEが使用できることも合わせて確認しておくと良い。
  3. 独自SSLの使用可否と固定IPアドレスを使用する際の追加料金、制限などについても確認。
    EC-CUBEは現バージョン(2009/01/17 ver.2.3.3)では、まだ共有SSLはほんの一部の特殊条件に当てはまる場合を除き使用できない。ショップとしてきちんとセキュリティ対策を行いながら運用したいのであれば、基本独自SSLを使用することになるだろうと思う。
    独自SSLを使用するために必要なのが、固定IPアドレスだ。ホスティングサービスによっては、1契約につき固定IPは1つしか使えない、ということがあり、または共有ホスティングサービスの場合は固定IPも独自SSLもそもそも全く使えない、ということが多い。複数のショップを同じサーバーのアカウントで運用したい場合もあると思う。そういった場合は複数の固定IPアドレスでそれぞれ独自SSLが使用できなければならないことになるので、この辺も確認しておきたい。(SSLでサブドメも含めたワイルドカードSSLを使用したい場合なら、ワイルドカードSSLが使用できるか確認しておいたほうが良いと思う。ワイルドカードSSLは高価だし、使用できるサーバーサービスも意外と少ない。専用サーバーを丸々1台借りて自由に設定できるSEがいれば別だろうけど、そうでなければ留意したほうがいいと思う。)
  4. まあ、特に後から引っかかりそうなところは↑この辺。あとは、SSHで接続できないサーバーの場合は、phpMyAdminなどDBの値を後から編集できるツールが使用できるか、など自分のスキルに合わせて細かく聞いておくと良いっすな。結構あとからDB触ったりカスタマイズしたりする必要性に見舞われることが多いので。。。

2)EC-CUBEパッケージのダウンロード

  1. EC-CUBEのホームページから、EC-CUBE2系→正式版をダウンロード、解凍しておく。ダウンロードするファイルをZIPにするかTAR.GZにするかは、自分が解凍しやすいほうでOK。普通WINDOWSユーザーはZIP、LINUXユーザーはTAR.GZをダウンロードする。
    ナイトリービルド版は、有志の開発者が日々新しい機能を組み込んだりバグを修正したりしている開発版なので、いち早く新しい機能を試したい、正式版でどうやっても解消できないバグが開発版で対策されている、といった場合には使用すると良い。ただし、あくまで開発中のベータ版であるのでテストなどが不十分なこともあるから、そのあたりは自己判断で。(ここでは正式版をDLしたものとして話を進める)
  2. パッケージの中身に抜けがないかチェックするため、念のためシステム要件や仕様、構成等をホームページを見ながら軽く確認。

3)PHPの設定。

PHPがapacheモジュール版の場合は、HTACCESSファイルで、CGI版の場合は、PHP.INIで、サーバーのPHP設定をEC-CUBE用に変更する。

  1. apache版の場合
    下記はいずれも、EC-CUBEのパッケージに入っているので、そのまま使用してかまわない。また、設定する値は自分の使用しているサーバーのデフォルトの値と矛盾するものだけセットすればいい。
    /html/のなかに、「.htaccess」ファイルを作成して、下記内容で保存。

    #基本はphp_ini.incで設定するが、ini_setで反映されないものはここで設定する
    php_value mbstring.language Japanese
    php_value output_handler mb_output_handler
    php_flag mbstring.encoding_translation 1
    php_flag magic_quotes_gpc 0
    #php_flag session.use_cookies 0
    #php_flag session.use_trans_sid 1
    # INI_ALL なのにもかかわらず, ini_set で指定しても反映されない環境がある…
    php_value mbstring.internal_encoding UTF-8
    # デフォルトテンプレートの状態で 2M近くになるため
    php_value upload_max_filesize 5M
    php_value date.timezone Asia/Tokyo

    /html/mobile/にも同様に、「.htaccess」ファイルを作成して、下記内容で保存。

    php_flag mbstring.encoding_translation 0
    php_value output_handler null
    php_value variables_order EGPS
    php_flag session.auto_start 0
    php_flag session.use_trans_sid 1
    php_value date.timezone Asia/Tokyo

  2. CGI版の場合
    設定する内容は「.HTACCESS」ファイルの場合と同じ。CGI版ではHTACCESSでのPHP設定の上書きができないため、php.iniで設定する。また、同様に、設定する値は自分の使用しているサーバーのデフォルトの値と矛盾するものだけセットすればいい。
    /html/の、phpスクリプトファイルが存在する全てのディレクトリに、「php.ini」ファイルを作成して、下記内容で保存。(※ルートのphp.iniだけ設定すれば良いサーバもあるが、mobileのほうではどのみち個別に設定しなければいけない)

    #基本はphp_ini.incで設定するが、ini_setで反映されないものはここで設定する
    mbstring.language= Japanese
    output_handler= mb_output_handler
    mbstring.encoding_translation= 1
    magic_quotes_gpc= 0
    #session.use_cookies= 0
    #session.use_trans_sid= 1
    mbstring.internal_encoding= UTF-8
    upload_max_filesize= 5
    date.timezone= Asia/Tokyo

    /html/mobile/にも同様に、「php.ini」ファイルを作成して、下記内容で保存。

    mbstring.encoding_translation= on
    output_handler= null
    variables_order= EGPS
    session.auto_start= off
    session.use_trans_sid= on
    date.timezone= Asia/Tokyo

4)サーバーのWEB公開領域にダウンロードしたEC-CUBEのパッケージをアップロードする。

  1. さて、ここでちょっと考えておくのがEC-CUBEのファイルディレクトリ構成。デフォルトでは、/html/と/data/の2つのディレクトリがあり、そのままアップロードして、/html/をwebサイトのデフォルトアクセスディレクトリに設定するんであるが、その構成に当てはまるサーバ(=つまりWEBの公開ルートディレクトリより上の階層にファイルを格納できるサーバ)は意外と少ない。
    ので、ここの構成を変えることにする。必要がない場合は、このステップはスキップね。
    今回は、/html/の中身をWEBのルートディレクトリ(メインのURL http://wwwdomain.com/などとして、アクセスできるWEB用の領域。通常は、/public_html/とか/web/とか/~user名/html/になっていると思う。)にアップロードし、/data/の中身は、その中に一階層下げてアップロードすることにする。
    /html/の中に、「define.php」というphpファイルがあるので、それを秀丸などのテキストエディタで開き、
    ——
    /** HTMLディレクトリからのDATAディレクトリの相対パス */
    define(“HTML2DATA_DIR”, “/data/“);
    /** DATA ディレクトリから HTML ディレクトリの相対パス */
    define(“DATA_DIR2HTML”, “../“);
    ——
    と変更。
  2. 「data」フォルダは、「html」フォルダの中に入れ、「html」フォルダを開いて、その中身のファイルを全てサーバーにアップロード。
  3. この時点でアップロードファイルの構成パターンは大体下記の3つ。
    • dataフォルダをhtmlフォルダの中に入れ、htmlはサーバのWEBルートディレクトリになっているパターン。
      (root)|—|about|  (htmlフォルダの中身)
      —|admin| (htmlフォルダの中身)
      —|data|
      —|その他のファイル| (htmlフォルダの中身)
    • /html/をWEBの公開ディレクトリに設定し、htmlフォルダとdataフォルダが平行してアップロードされているパターン。
      |html|—|about|
      —|admin|
      —|その他のファイル|
      |data|  (※htmlと同じ階層)
    • /html/の中身をWEBの公開ディレクトリに設定し、dataフォルダは、それと同階層になるように、WEBの公開ディレクトリより1段上の階層にアップロードされているパターン。
      (root)|—|about| (htmlフォルダの中身)
      —|admin| (htmlフォルダの中身)
      —|その他のファイル| (htmlフォルダの中身)
      |data|  (※htmlの中身=rootより1段上の階層)

5)データベースの作成と事前設定。

  1. まずは、EC-CUBE用のデータベースを作成する。
  2. 作成できたら、データベース内の文字化けを防ぐため、DB内のデフォルトの文字コード設定を確認、修正しておく。
    まずは、現状のデフォルト文字コードを確認。
    phpMyAdminで下記のSQLコードを実行し、現在サーバーで使用されている文字コードを確認する。

    show variables like “char%”;

    serverphp

    システムの文字コード以外は全てutf-8になっているか確認。(システム文字コードもUTF-8であればそれはそれでかまわない) 

  3. DBの文字コードがUTF-8になっていない場合は、再びSQLで、

    alter database 〜DB名 character set utf8;

    と打ち込んで文字コードを変更。変更後、先のshowコマンドで再びチェックしておく。
    上記のように正しく変更されていればOK。

  4. このままでは、スクリプトを起動したタイミングで文字コードはサーバーのデフォルトに戻ってしまうので、スクリプトにもコードを追加する。
    /data/class/SC_DbConn.phpの65行目あたりに下記コードを追加しておく。(多分、新しいバージョンのEC-CUBEであれば、ここはパッケージソース自体が修正されていると思う。一応確認。)

    if(defined(‘DEFAULT_DSN’)) {
    $objDbConn = DB::connect(DEFAULT_DSN, $options);
    $this->dsn = DEFAULT_DSN;
    } else {
    return;
    }
    }
    }
    if (DB_TYPE == ‘mysql’) {
    $objDbConn->query(‘SET NAMES utf8′);
    }

    $this->conn = $objDbConn;

これで、いよいよインストール。

6)ブラウザから、EC-CUBEをインストールするURLを開く。インストーラの手順に沿ってインストール。

  1. インストールが正常に完了したら、再び/data/class/SC_DbConn.phpを開き、
    $this->conn = $objDbConn;の下(先のコードのL69辺り)に
    $this->conn->query(“SET time_zone = ‘Asia/Tokyo’”);
    と追記して、保存。上書きアップロード。
    ※国内サーバの場合は、タイムゾーンはすでにアジアになっているだろうから、その場合はこの設定は不要。

7)管理画面からショップの設定を行う。

先に、基本情報と特定商取引法に関する表記を入力。その後、「郵便番号DB登録」をクリック。郵便番号辞書はすごいデータ量なので、途中で何とかサーバーエラーが表示されたり画面が真っ白になることがある。
そういう時は、phpMyAdminで、mtb_zipテーブルを確認してみて、その中のデータが増えていれば、問題なく登録されていっていると考えていいので、最終的に、ブラウザで完了画面が出るまで休み休みしながら何度か繰り返しページをリロードし続ける。

完了したら、再びphpMyAdminからmtb_zipテーブルの中身を確認して、データ登録が沖縄県まで全て完了しているか確認しておこう。

最後にメールの送信テスト。
ECサイトのお問い合わせから別のメールアドレスで問合せメールを送ってみて、正常に送信(管理者とお客様双方に確認メールが届く)されればメールはOK。
もし、送信されない場合は、ブラウザからEC-CUBEの管理画面にアクセスして、システム管理画面のパラメータ設定で、「MAIL_BACKEND」の値を”smtp”から”mail”または”sendmail”に変更してみる。たいていは、「mail」で送信できるようになると思う。

大体ここまでで、クリーンインストールでトラブルになる点を解消したインストールができていると思う。カスタマイズを行う前に、フロント画面でログインや注文動作などチェックしておく。

【EC-CUBE】海外サーバーの時差をなんとかする(表現、ビミミョ~;)

海外サーバを使ってEC-CUBEを運営しているので、ここで時差になやまされる。

ワードプレスとかみたいなワールドワイドに結構作りこまれているソフトだとタイムゾーンを管理画面から調整できるのだけど、EC-CUBEは純国産だからか、そういう機能は残念ながら無い;

時差を吸収するためには、2つの対策が必要。

1つめ)PHPの扱う時間。これは受注メールを送ったりといったときに出てくることになる。
2つめ)DBが扱う時間。こっちは、受注した時間や管理画面を操作した時間なんかが登録される。

1つ目の対策→php.iniに、タイムゾーンを書く。

2つ目の対策→/data/class/SC_DbConn.phpの
「$this->conn = $objDbConn;」の1行後ろに、
「$this->conn->query(“SET time_zone = ‘Asia/Tokyo’”);」を追加。

これで、DBに格納される受注日などは日本のタイムゾーンで登録される。

先に既に登録されているものは変更されないので、手動で変更。

【EC-CUBE】SMARTYでマルチバイト文字を丸める(字数制限を利用する)

SMARTYのテンプレートで商品説明などを表示するときに、レイアウト上、前から10文字だけを表示してあとは、「…」という感じで表示する文字数を合わせたいときに利用する。

前から何文字目から何文字、といったように文字を丸めるわけだが、日本語の場合マルチバイトなので、PHPで本来の丸めにつかうtrancate()が利用できないので、mb_strimwidth()を使う。

それをSMARTY上で、利用することになる。

例:

{$hoge|mb_strimwidth:0:40:”…”|escape}

『$hogeの文字列の最初から(=0)、40字(=40)を表示し、一番最後は「…」と表示する。』という意味。
注意しておくのは、どうやら、この40字、マルチバイトは半角の2文字なので、つまりは、これで20文字ということになる模様。なるほど。

これ、結構使えるなぁ。

参考:
http://www.php-seed.net/blog/archives/118
http://www.phppro.jp/phpmanual/php/function.mb-strimwidth.html

【EC-CUBE】テンプレートの中に別のテンプレート(ブロック)を呼び込む記述

1)管理画面からブロック(tempA)を作る。 (※既存のテンプレブロックの場合は、これは不要)

2)読み込む側のテンプレのソースにインクルード用のコードを記述する。

<!–{assign var=tempA value=$smarty.const.USER_TEMPLATE_PATH|cat:”default/bloc/tempA.tpl“}–>
<!–{include file=$tempA}–>

重要!)先に変数にアサインしてから、インクルードすること。上記ソース参照。
下記でも可能。

<!–{include file=`$smarty.const.USER_TEMPLATE_PATH`default/bloc/tempA.tpl}–>

【EC-CUBE】テンプレを変更してもブロックレイアウト情報を設定したとおりに再現する

EC-CUBEでは、ブロックのデフォルトレイアウトが、update_block.sqlのSQL文によって設定されている。

管理画面でレイアウトを決めても、テンプレートを変更したり、キャッシュをクリアした場合、ブロックレイアウトの情報をこのupdate_block.sqlから新規に読み込んできてしまうため、その都度デフォルトのブロックレイアウトに変わってしまう。

これじゃあ、イタチのおっかけっこってやつじゃあないですかい?
ってことで、一旦リリースしたWEBサイトでは、次にテンプレ更新したときも、やっぱり同じブロックレイアウトで表示されたいですな、ってことで、どん。

update_block.sqlは、
/data/smarty/templates/(テンプレ名)/_packages/sql/
/user_data/packages/(テンプレ名)/sql/
/user_data/packages/default/sql/
にそれぞれあるので、ここの値を変更。

テンプレの更新時に読み込んでもらいたいなら(Aのテンプレでは、Aのブロックレイアウトセットを使うけど、違うテンプレのときには違うブロックレイアウトセットを使うときは)/data/smarty/templates/(テンプレ名)/_packages/sql/のなかのupdate_block.sqlのみ編集。

下記に編集ルールをば。

INSERT INTO dtb_blocposition (page_id,target_id,bloc_id,bloc_row,filename)values(1,5,1,0,’category’);

これは、前から、

  • page_id→
  • target_id→5
  • bloc_id→1
  • bloc_row→0
  • filename→category

と設定されているということで、

page_id トップページ=1、一覧ページ=2、詳細ページ=3、マイページ=4、その他カスタムで作成したページへID付与。(dtb_pagelayout参照)
target_id 左カラム=1、中央上カラム=2、右カラム=3、中央下カラム=4、未使用ブロック=5.mtb_target参照)
bloc_id カテゴリー=1、利用ガイド=2、かごの中=3等。(dtb_bloc参照)
bloc_row カラム内でのブロックの表示優先順位。0は非表示で、target_idに5(未使用ブロック)が選択されている場合に設定可能。
filename カテゴリー=1、利用ガイド=2、かごの中=3等。(dtb_bloc参照)bloc_idと対応している。

つまり、上記の文では、トップページでは、カテゴリーブロックが未使用、ということ。

自分で、決めたレイアウトどおりにブロックの配列を記載しておくとよい。

新規ページを作成した場合、そのブロックの設定は、データベースのdtb_blocpositionに保存されるので、テンプレが更新されてもリセットはされない。デフォルトの各ページのみこのSQLの影響を受ける。もちろん新規ページについても同SQL内で設定しておくことも可能。

【EC-CUBE】入力欄の許可タグ

入力欄の許可タグ・・・

許可されてる種類が異様に少ない・・・

<li>は許可されて、<ol>とか<ul>入ってないって、どういうこと!?
<span>ないってどういうこと!?
<th>はあかんのか!?

・・・・・追加。

DBのmtb_allowed_tagに、追加したいタグのそれぞれ開始タグと終了タグを登録する。
PhpMyAdminでDBにアクセスして、mtb_allowed_tagを探してデータ編集。
IDとRANKは、データの一番後ろから連番で追加していくこと。

インストールのときから、増やしときたい場合は、インストールのところのプログラムをイジイジ。(とりあえず、今は、先にインストールされたEC-CUBEのカスタマイズのハナシなんで、こっちのハナシは一旦無視。)

登録できたら、/data/cache/の中の「mtb_allowed_tag.php」削除して、一応管理画面もログアウトしてから再ログイン。

これで、タグ許可の入力エリアに入力できるタグの種類が増えた♪

【EC-CUBE】ヘッダーにトップページだけメインビジュアルをででんと表示する

トップページに大きくメインビジュアルを表示させる場合(ホラ、あれよ、アレ。メインビジュアルどど~ん、ってやつよ。フラッシュとか。)site_main.tplやtop.tplにいれるとカラムの影響を受けてしまうので、header.tplへトップページの場合のみエリアを表示させる変更を入れることにする。

該当出力ページが、サイトのトップページ(/index.php)だったら、<div id=”mainvisual”></div>を表示。
それ以外だったら、この部分には何も表示しない。

<!–{if $smarty.server.PHP_SELF == “/index.php”}–>
<div id=”mainvisual”>(この中にフラッシュのソース他コンテンツを入れる)</div>
<!–{else}–><!–[if}–>

以上だす。

【EC-CUBE】携帯用詳細コメントを追加する

データベースに携帯用コメントカラムを追加し、商品登録時に、携帯用には別の詳細説明を登録し、PCサイトの説明と別にする。

  • データベースにカラム(フィールド)追加
  • 商品登録のPHPスクリプト追加
  • 管理画面の商品登録・確認テンプレートを修正
  • モバイル用詳細テンプレートを修正

その1)データベースへのカラム追加

phpMyAdminでDBへアクセスし、dtb_productsの最後へ1カラム追加。

カラム名「comment7」
データ型「text」

※残りのフィールドは先のデータを参照。

その2)商品登録PHPの修正。

/data/class_extends/page_extends/admin/products/LC_Page_Admin_Products_Product_Ex.php

/data/class/pages/admin/products/LC_Page_Admin_Products_Product.phpからlfRegistProduct関数 (=商品登録関数)をコピー(L387~L493:ver.2.3.2の場合)し、LC_Page_Admin_Products_Product_Ex.phpの「デストラクタ」の下(L68:ver.2.3.2の場合※最後の「}」の手前へ。)へ貼り付け。
ソースを一部編集する。

貼り付けたソースのL78あたりにcomment7(=携帯用コメント)を追加。

 ”comment4″, “comment5″, “comment6″, “comment7″, “main_list_comment”,

L97あたりにも1行追加。

$sqlval['comment7'] = $arrList['comment7'];

LC_Page_Admin_Products_Product.phpからLC_Page_Admin_Products_Product_Ex.phpへ、lfErrorCheck関数もコピー。(L546~L609:ver.2.3.2の場合)
lfRegistProduct関数の下に貼り付け。

貼り付けたソースのL183あたり
$objErr->doFunc(array(“詳細-メインコメント”, “main_comment”, $this->arrAllowedTag), array(“HTML_TAG_CHECK”));
の下に2行追加。

$objErr->doFunc(array(“携帯用詳細コメント”, “comment7″, LLTEXT_LEN), array(“SPTAB_CHECK”, “MAX_LENGTH_CHECK”));
$objErr->doFunc(array(“携帯用詳細コメント”, “comment7″, $this->arrAllowedTag), array(“HTML_TAG_CHECK”));

その3)MySql用にデータの読み込みコードを追加

これをやらないと、再編集するときに、登録画面に以前に登録したデータが読み込まれない;

/data/class/db/dbfactory/SC_DB_DBFactory_MYSQL.php (L304あたり:ver.2.3.3の場合)

「T1.comment6,」の下に1行追加し、「T1.comment7,」。

その4)データ登録用ADMINテンプレートの編集。

商品登録画面のテンプレートへ携帯用情報登録フォームのコード追加。

/data/Smarty/templates/default/admin/products/product.tpl (L243あたり、詳細-メインコメントのTD中へ。)

 <br><br>
 <div class=”center”>
  <input type=”button” name=”btn” onclick=”selectAll(‘category_id’); lfDispSwitch(‘mobile_detail’);” value=”モバイル専用詳細コメント表示/非表示”>
 </div>
 <div id=”mobile_detail” style=”<!–{if !$arrForm.comment7}–>display:none<!–{/if}–>”>
  <p>
  PCと携帯で異なる詳細コメントを表示する際には以下のフォームに携帯サイト用のコメントを入力して下さい。<br />
  入力されなかった場合は、PCサイトと同じ詳細コメント↑を表示します。<br />
  </p>
  <textarea name=”comment7″ id=”comment7″ value=”<!–{$arrForm.comment7|escape}–>” maxlength=”<!–{$smarty.const.LLTEXT_LEN}–>” style=”<!–{if $arrErr.comment7 != “”}–>background-color: <!–{$smarty.const.ERR_COLOR}–><!–{/if}–>”  cols=”60″ rows=”8″ class=”area60″><!–{$arrForm.comment7|escape}–></textarea><br /><span class=”red”> (上限<!–{$smarty.const.LLTEXT_LEN}–>文字)</span>

確認画面は、携帯用コメントを入力した場合のみ表示されるようにコードを追加。

/data/Smarty/templates/default/admin/products/confirm.tpl (L183あたり、詳細-メインコメントの/TRの後ろへ。)

<!–{if $arrForm.comment7}–>
<tr>
 <td bgcolor=”#f2f1ec” width=”160″ class=”fs12n”>モバイル詳細コメント</td>
 <td bgcolor=”#ffffff” width=”557″ class=”fs12n”>
 <!–{$arrForm.comment7|nl2br}–>
 </td>
</tr>
<!–{/if}–>

その5)モバイルサイトの表示テンプレートを編集。

/data/Smarty/templates/default/mobile/products/detail.tpl (L39あたり。詳細メインコメントの表示を変更。)

<!–{$arrProduct.main_comment|nl2br}–>

↓下記に変更。

<!–{if !$arrProduct.comment7}–><!–{$arrProduct.main_comment|nl2br}–><!–{else}–><!–{$arrProduct.comment7|nl2br}–><!–{/if}–>

携帯専用のコメントがある場合は、それを表示し、ない場合は、PC用のコメントを共用で表示する。

参考:http://www.eccube-school.jp/products/detail40.html
※DBがポスグレの場合は、上記手順と少し違うため、こちらのサイトを参照のこと。

【EC-CUBE】受注管理でデータの更新ができない場合にエラーメッセージを出す

受注データの更新ができていなくてもアラートがでなかったのを、ちゃんとエラーメッセージが出るようにする。(エラーなく更新できるようにバグ修正するわけではないので誤解なきよう注意。)

/data/class/pages/admin/order/LC_Page_Admin_Order_Edit.php

L151あたりの

   if(count($this->arrErr) == 0) {
       $this->lfRegistData($_POST['order_id']);
       // DBから受注情報を再読込
       $this->lfGetOrderData($order_id);
       $this->tpl_onload = “window.alert(‘受注履歴を編集しました。’);”;
     }

これを↓下記に。

   if(count($this->arrErr) == 0) {
      $this->lfRegistData($_POST['order_id']);
      // DBから受注情報を再読込
      $this->lfGetOrderData($order_id);
      $this->tpl_onload = “window.alert(‘受注履歴を編集しました。’);”;
    } else {
       $this->tpl_onload = “window.alert(‘受注履歴が編集できませんでした。”.array_shift($this->arrErr).”‘);”;
    }

【EC-CUBE】売り上げ集計をバッチモードにして動作を軽減(再びCRON)

EC-CUBEの売り上げ集計は2つのモードが選択でき、デフォルトは、リアルタイム集計。処理が長くなると、タイムアウトしてしまったり、ダウンしてしまう。

  1. リアルタイム・・・「月度で集計する」や「期間で集計する」ボタンが押されたときにその場で集計→集計データ格納→集計データ取得→表示、と行う方法。
  2. バッチモード・・・あらかじめ売上データを集計しておき、「月度で集計する」や「期間で集計する」ボタンが押されたときには、すでに集計して格納済みのデータを取得→表示、と行う方法。

その1)管理モードの変更

管理画面→システム管理→パラメータ管理で、
DAILY_BATCH_MODEを[false]から[true]に変更。

その2)/data/script/execute_batch_daily.phpを作成。

/**
* デイリーバッチ起動スクリプト
*/

require_once( dirname(__FILE__) . “/../install.php” );
define( “CLASS_PATH”, DATA_PATH . ‘class/’ );
define( “CLASS_EX_PATH”, DATA_PATH . ‘class_extends/’ );
define( “CACHE_PATH”, DATA_PATH . ‘cache/’ );

require_once(CLASS_EX_PATH . “util_extends/GC_Utils_Ex.php”);
require_once(CLASS_EX_PATH . “util_extends/SC_Utils_Ex.php”);
require_once(CLASS_EX_PATH . “db_extends/SC_DB_MasterData_Ex.php”);
require_once(CLASS_EX_PATH . “db_extends/SC_DB_DBFactory_Ex.php”);
require_once(CLASS_PATH . “SC_DbConn.php”);
require_once(CLASS_PATH . “SC_Query.php”);
require_once(CLASS_PATH . “SC_SelectSql.php”);

require_once(CLASS_EX_PATH . ‘batch_extends/SC_Batch_Daily_Ex.php’);
require_once(CLASS_EX_PATH . “SC_Initial_Ex.php”);
// アプリケーション初期化処理
$objInit = new SC_Initial_Ex();
$objInit->init();

$usage = <<

php -f execute_batch_daily.php start term
集計期間を指定して売上集計をします。

 start 集計開始日。何日前の売上から集計するか。1 から 365以内で指定。
 term 集計対象期間。何日分の売上を集計するか。1 から 365以内で指定。

例:昨日の売上を集計します。
php -f execute_batch_daily.php 1 1

USAGE;

if ( $argc != 3 ) {
echo ( $usage );
exit(1);
}

$start = $argv[1];
$term = $argv[2];
if ( !is_numeric( $start ) || !is_numeric( $term ) ) {
echo ( $usage );
exit(1);
}

$start = intval( $start );
$term = intval( $term );

if ( $start < 1 || $start > 365 || $term < 1 || $term > 365 ) {
echo ( $usage );
exit(1);
}

if ( $term > $start ) {
echo ( $usage );
exit(1);
}

$objBatch = new SC_Batch_Daily_EX();
$objBatch->lfStartDailyTotal( $term, $start, true );
?>

その3)/data/class/batch/SC_Batch_Daily.phpを修正。

L92,93(ver.2.3.2の場合)

// 削除された受注データの受注詳細情報の削除
$objQuery = new SC_Query();
//$where = “order_id IN (SELECT order_id FROM dtb_order WHERE del_flg = 1)”; ←コメントアウト
//$objQuery->delete(“dtb_order_detail”, $where); ←コメントアウト

// 最後に更新された日付を取得

// 最後に更新された日付を取得

L102(ver.2.3.2の場合)

// 最後のバッチ実行からLOAD_BATCH_PASS秒経過していないと実行しない。
if($pass < LOAD_BATCH_PASS) {
//GC_Utils_Ex::gfPrintLog(“LAST BATCH ” . $arrRet[0]['create_date'] . ” > ” . $batch_pass . ” -> EXIT BATCH $batch_date”); ←コメントアウト
$batch_next = date( “Y-m-d H:i:s”, strtotime($batch_last) + LOAD_BATCH_PASS ); ←追加
GC_Utils_Ex::gfPrintLog(“LAST BATCH ” . $batch_last . ” NEXT BATCH AFTER $batch_next -> EXIT BATCH”); ←追加

return;
}

L107(ver.2.3.2の場合)

// 集計
//for ($i = $start; $i < $term; $i++) { ←コメントアウト
for ($i = $start, $k = 0; $k < $term; $i–, $k++ ) { ←追加
// 基本時間から$i日分さかのぼる
$tmp_time = $now_time – ($i * 24 * 3600);

L154(ver.2.3.2の場合)

GC_Utils_Ex::gfPrintLog(“LOADING BATCH $batch_date”);
$this->lfBatOrderDaily($tmp_time);
$this->lfBatOrderDailyHour($tmp_time);
$this->lfBatOrderAge($tmp_time);
// タイムアウトを防ぐ ←追加
SC_Utils_Ex::sfFlush(); ←追加

}
}

※そもそも集計時にSQLエラーになるところがあるので、先に
http://www.bton.net46.net/?p=724
の修正を行っておくこと。

その4)CRONの設定

0 2 * * * /usr/local/bin/php -f /path/to/eccube/data/script/execute_batch_daily.php 1 1 2>&1 > /dev/null

参考サイト:http://d.hatena.ne.jp/yuhei_kagaya/20081019

【EC-CUBE】集計ページが正しく表示されない・・・対応策の備忘録

集計表示でタイムアウト・・・デフォルトではリアルタイム集計をしているので、動作が重くサーバに負荷も掛かってしまう。

思い切ってバッチ処理で夜中に前日までの売り上げを集計しておくことにする。これで、集計を見るときにはサックサク動くはず。

と思ったら、いくつかバグがあり、MYSQLを使っていると、バグを踏んでるいくつかの集計は表示されない。エラーでまくり、なんだこりゃ。全体的に、MYSQL関係でなんだかんだとエラーが出るんだね。

てことで、バッチ処理にする手前で、虫退治に出かけることになる。。。

表示できなかったのは、mySQLを使用した際、ポスグレでは利用できるtrunc関数をmySQL用にtruncate関数へ変換する処理が上手く機能していないため。

そこで、シンタックスエラーになっていたSQL構文を修正し、動作不良を修正。その後、MYSQL用にtrunc→truncate変換をしているsfChangeMySQLが2重に掛かっている(と思われる)部分をコメントアウト。コレで何とかサクサク動作を手に入れた;

その1)シンタックスエラーの修正。

/data/class/batch/SC_Batch_Daily.php (L189、L271:ver.2.3.2の場合)

/data/class/pages/admin/total/LC_Page_Admin_Total.php (L641、L709:ver.2.3.2の場合)

上記2つのファイルの(AVG(total))→(AVG(total),0)へ変更
この時点で、エラーの出ていた職業別集計と会員別集計のうち職業別集計は表示されるようになる。

その2)trunc→truncate変換をしているsfChangeMySQLの2重適用部分をコメントアウト。

/data/class/SC_Query.php (L94:ver.2.3.2の場合)

この中の、$sqlse = $dbFactory->sfChangeMySQL($sqlse); 1行をコメントアウト(または削除)

※/data/class/SC_Query.phpの$sqlseというのが、なんに使われているのか分からなかったが、ここでは、sfChangeMySQLの処理を行っているだけで、同じ処理がSC_DbConnでも順に行っていることから不要かと判断する。

これで動作はエラーがなくなった。
あとはバッチ処理で夜中にcronを動かすのみ。だ~~~~~。

【EC-CUBE】ギフト・熨斗対応オプション追加のカスタマイズ

概要

  • ギフト包装の種類は、管理画面>基本情報管理>マスタデータ管理で変更可能にする。
  • ギフト包装が有料の場合にも対応する。ただし、有料ギフト包装の金額はポイント対象外。
  • ギフト包装の金額は、管理画面>基本情報管理>マスタデータ管理で変可能にする。
  • MYページの購入履歴画面や注文完了メール内に、選択したギフト包装の種類と金額を載せる。
  • ロジックの変更はあるが、それは全部継承で対応する方針で親のクラスには手を入れない。

データベースの変更と追加

DBは、mtb_*がマスタ系のデータとなっており、mtb_*の名称のものは、管理画面>システム設定>マスタデータ管理で変更できるが、mtb_pref、mtb_zip、mtb_constants はマスタ管理からはずされている。(それについての記載は、LC_Page_Admin_Basis_Masterdata.php::getMasterDataNames() にある。)

ギフト包装の種類のマスタテーブルを作る

DBへmtb_giftテーブルを追加し、
id smallint(6)  NOT NULL  default値:0
name text
rank smallint(6)  NOT NULL  default値:0
のフィールドを作り、プライマリーキーをidにする

下記SQL文でも作成できる。

CREATE TABLE `mtb_gift` (
  `id` smallint(6) NOT NULL default ’0′,
  `name` text,
  `rank` smallint(6) NOT NULL default ’0′,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ギフト包装の税込金額を定数で設定する

DBのmtb_constantsテーブル最後尾にフィールドを1行追加し、
GIFT_PRICE 200 523 ギフト包装の税込価格
というように、値をセットする。

上記の場合、
1つ目のidが定数名。
2つ目のnameに入れるのが定数の値。今回の場合はギフト包装の税込金額を200円とした。
3番目のrankに入れるのが管理画面での表示順。今入っているレコードの最大+1だと一番下に表示される。
4番目のremarkに入れるのが管理画面でパラメータ入力欄の上に灰色で小さく出るパラメータの説明文

下記SQL文でも作成できる。

INSERT INTO `mtb_constants` values(‘GIFT_PRICE’, ’200′, ’523′, ‘ギフト包装の税込価格’);

次に、管理画面>システム設定>パラメータ設定へアクセスし、値は変えなくていいので、そのまま一度「この内容で登録する」ボタンをクリックする。

これによって、マスタテーブルから値を読み出して定数設定を行うPHPファイルにDBで変更した値がセットされ、DBの内容をキャッシュしているファイルが更新される。(=/data/cache/mtb_*.php)

ギフト包装の種類を入力。

先に作成したmtb_giftに管理画面からギフト包装の種類を登録していく。

管理画面>システム設定>マスタデータ管理で、先ほど作成したmtb_giftを選択し、ギフト包装の種類を順番に登録。(ID=0はギフトなしとして使うので、登録せず、1から登録すること。)

受注データ内に、ギフト情報をどのように格納するかを考える。

受注テーブル(dtb_order)や、一時的な受注テーブル(dtb_order_temp)で、text型のmemo1~memo10という汎用項目として使える列があり、memo1~4あたりは既に使ってるらしいので、memo09とmemo10を使ってギフト情報を格納する。(作業は後に)

memo09・・・ギフト包装の種類。0はギフト包装なし。
memo10・・・受注したときのギフト包装の価格。

ここまでで、ギフト包装の価格の変更も管理画面でのパラメータ設定でできるようになった。

お支払方法・お届け時間等の指定画面

購入フローのお支払方法・お届け時間等の指定画面でギフト選択のリストが表示されるようにする。

PCサイトのテンプレートの修正

/data/Smarty/templates/default/shopping/payment.tpl

に以下のコードを追加。(ver.2.3.2の場合L89あたりがよい。表示させたい位置でOK。)

<div class=”payarea02″>
<h3><img src=”<!–{$TPL_DIR}–>img/shopping/subtitle04.gif” width=”670″ height=”33″ alt=”ギフト包装と熨斗の指定” /></h3>
<p>ギフト包装をご希望の方は、選択してください。</p>
<div>
<!–{assign var=key value=”memo09″}–>
<span class=”attention”><!–{$arrErr[$key]}–></span>
<select name=”<!–{$key}–>” style=”<!–{$arrErr[$key]|sfGetErrorColor}–>”>
<option value=”0″ selected=”selected”>ギフトなし</option>
<!–{html_options options=$arrGift selected=$arrForm[$key].value}–>
</select>
</div>
</div>

ギフト包装と熨斗の指定用のタイトル画像も作ること。

モバイルサイトのテンプレートの修正

data/Smarty/templates/default/mobile/shopping/deliv_date.tpl

に以下のコードを追加。(ver.2.3.2の場合L41あたりがよい。表示させたい位置でOK。)

■ギフト包装と熨斗の指定<br />
<!–{assign var=key value=”memo09″}–>
<!–{if $arrErr[$key] != “”}–>
<font color=”red”><!–{$arrErr[$key]}–></font>
<!–{/if}–>
<select name=”<!–{$key}–>”>
<option value=”0″>ギフトなし</option>
<!–{html_options options=$arrGift selected=$arrForm[$key].value}–>
</select>

ショッピング用ページクラスの拡張

/data/class_extends/page_extends/shopping/LC_Page_Shopping_Payment_Ex.php

init()、lfInitParam()、lfSetOrderTempData()のコードを追加する。

L47(ver.2.3.2の場合)
    function init() {
        parent::init();
のあたりから、

    function init() {
        parent::init();
        $this->tpl_title = “お支払方法・お届け時間・ギフト包装の指定”;
        $masterData = new SC_DB_MasterData_Ex();
        $this->arrGift = $masterData->getMasterData( “mtb_gift”,
                                array( “id”, “name”, “rank” ) );
    }

    function lfInitParam() {
        parent::lfInitParam();
        $this->objFormParam->addParam( “ギフト・のし”, “memo09″, INT_LEN, “n”, array( “MAX_LENGTH_CHECK”, “NUM_CHECK”) );
       
    }

    //一時受注テーブルからの情報を格納する
    function lfSetOrderTempData($uniqid) {

        $objQuery = new SC_Query();
        $col = “payment_id, use_point, deliv_time_id, message, point_check, deliv_date, memo09″;
        $from = “dtb_order_temp”;
        $where = “order_temp_id = ?”;
        $arrRet = $objQuery->select($col, $from, $where, array($uniqid));
        // DB値の取得
        $this->objFormParam->setParam($arrRet[0]);
        return $this->objFormParam;
    }

とコードを追加。

ご入力内容の確認画面

注文内容の欄に、前の画面で選択したギフト包装の種類と価格を含めるようにし、ギフトなしの場合はこの行自体を表示させないようにする。

PCサイトのテンプレートの修正

/data/Smarty/templates/default/shopping/confirm.tpl

L103あたりから(手数料の下へ:表示させたい場所へ入れてOK)(ver.2.3.2の場合)

<!–{if $arrData.memo09 gt 0}–>
        <tr>
          <th colspan=”4″ class=”resulttd”>ギフト包装 : <!–{$arrGift[$arrData.memo09]}–></th>
          <td class=”pricetd”><!–{$smarty.const.GIFT_PRICE|number_format}–>円</td>
        </tr>
<!–{/if}–>

モバイルサイトのテンプレートの修正

/data/Smarty/templates/default/mobile/shopping/confirm.tpl

L49あたりから(配送先の下へ:表示させたい場所へ入れてOK)(ver.2.3.2の場合)

<!–{if $arrData.memo09 gt 0}–>
■ギフト包装(<!–{$arrGift[$arrData.memo09]}–>):<!–{$smarty.const.GIFT_PRICE|number_format}–><br><!–{/if}–>

<br>

L84あたりにもフォーム用のコードを1行追加。

<input type=”hidden” name=”memo09″ value=”<!–{$arrData.memo09}–>”>

ページクラスの拡張

/data/class_extends/page_extends/admin/order/LC_Page_Shopping_Confirm_Ex.php

init()以下へコードを追加。L48あたりから。

    function init() {
        parent::init();
        $masterData = new SC_DB_MasterData_Ex();
        $this->arrGift = $masterData->getMasterData( “mtb_gift”,
                                array( “id”, “name”, “rank” ) );
    }

会計ロジックの拡張

/data/class_extends/helper_extends/SC_Helper_DB_Ex.php

L36からの
class SC_Helper_DB_Ex extends SC_Helper_DB {
(この間にコードを追加)

    /**
     * 集計情報を元に最終計算を行う.
     *
     * @param array $arrData 各種情報
     * @param LC_Page $objPage LC_Page インスタンス
     * @param SC_CartSession $objCartSess SC_CartSession インスタンス
     * @param array $arrInfo 店舗情報の配列
     * @param SC_Customer $objCustomer SC_Customer インスタンス
     * @return array 最終計算後の配列
     */
    function sfTotalConfirm($arrData, &$objPage, &$objCartSess, $arrInfo, $objCustomer = “”) {
        $arrData = parent::sfTotalConfirm($arrData, &$objPage, &$objCartSess, $arrInfo, $objCustomer = “”);
       
        // ギフト包装の計算。0はギフト包装なしのこと。
        if ( intval( $arrData["memo09"] ) > 0 ) {
            $arrData['payment_total'] += GIFT_PRICE;
            $arrData['memo10'] = GIFT_PRICE;
        } else {
            $arrData['memo10'] = 0;
        }
       
        return $arrData;
    }

購入履歴画面

PCサイトのテンプレートの修正

/data/Smarty/templates/default/mypage/history.tpl

L88あたり(手数料の下あたり:表示させたい場所へ入れてOK)(ver.2.3.2の場合)

<!–{if $arrDisp.memo09 != “” && $arrDisp.memo09 gt 0}–>
      <tr>
        <th colspan=”4″ class=”resulttd”>ギフト包装 : <!–{$arrGift[$arrDisp.memo09]}–></th>
        <td class=”pricetd”><!–{$arrDisp.memo10|escape|number_format}–>円</td>
      </tr>
<!–{/if}–>

モバイルサイトのテンプレートの修正

/data/Smarty/templates/default/mobile/mypage/history_detail.tpl

L55あたり(ご注文内容の下あたり:表示させたい場所へ入れてOK)(ver.2.3.2の場合)

<!–{if $arrDisp.memo09 != “” && $arrDisp.memo09 gt 0}–>
【ギフト包装】(<!–{$arrGift[$arrDisp.memo09]}–>):<!–{$arrDisp.memo10|escape|number_format}–>円<br>
<!–{/if}–>
<br>

ページクラスの拡張

PCページ用のクラス

/data/class_extends/page_extends/mypage/LC_Page_Mypage_History_Ex.php

init()、lfGetOrderData()コードの追加。

L46あたりから。(ver.2.3.2の場合)

    function init() {
        parent::init();
        $masterData = new SC_DB_MasterData_Ex();
        $this->arrGift = $masterData->getMasterData( “mtb_gift”,
                                array( “id”, “name”, “rank” ) );
    }

    //受注詳細データの取得
    function lfGetOrderData($order_id) {
        //受注番号が数字であれば
        if(SC_Utils_Ex::sfIsInt($order_id)) {
            // DBから受注情報を読み込む
            $objQuery = new SC_Query();
            $col = “order_id, create_date, payment_id, subtotal, tax, use_point, add_point, discount, “;
            $col .= “deliv_fee, charge, payment_total, deliv_name01, deliv_name02, deliv_kana01, deliv_kana02, “;
            $col .= “deliv_zip01, deliv_zip02, deliv_pref, deliv_addr01, deliv_addr02, deliv_tel01, deliv_tel02, deliv_tel03, deliv_time_id, deliv_date, memo09, memo10 “;
            $from = “dtb_order”;
            $where = “order_id = ?”;
            $arrRet = $objQuery->select($col, $from, $where, array($order_id));
            $arrOrder = $arrRet[0];
            // 受注詳細データの取得
            $arrRet = $this->lfGetOrderDetail($order_id);
            $arrOrderDetail = SC_Utils_Ex::sfSwapArray($arrRet);
            $arrData = array_merge($arrOrder, $arrOrderDetail);
        }
        return $arrData;
    }

モバイルサイト用にもおなじように拡張。

/data/class_extends/page_extends/mypage/LC_Page_Mypage_HistoryDetail_Ex.php

L50あたりから。 ※モバイル用のinitであることに注意。その上にPC用のinitがある!

    function mobileInit() {
        parent::mobileInit();
        $masterData = new SC_DB_MasterData_Ex();
        $this->arrGift = $masterData->getMasterData( “mtb_gift”,
                                array( “id”, “name”, “rank” ) );
    }

    //受注詳細データの取得
    function lfGetOrderData($order_id) {
        //受注番号が数字であれば
        if(SC_Utils_Ex::sfIsInt($order_id)) {
            // DBから受注情報を読み込む
            $objQuery = new SC_Query();
            $col = “order_id, create_date, payment_id, subtotal, tax, use_point, add_point, discount, “;
            $col .= “deliv_fee, charge, payment_total, deliv_name01, deliv_name02, deliv_kana01, deliv_kana02, “;
            $col .= “deliv_zip01, deliv_zip02, deliv_pref, deliv_addr01, deliv_addr02, deliv_tel01, deliv_tel02, deliv_tel03, deliv_time_id, deliv_date, memo09, memo10 “;
            $from = “dtb_order”;
            $where = “order_id = ?”;
            $arrRet = $objQuery->select($col, $from, $where, array($order_id));
            $arrOrder = $arrRet[0];
            // 受注詳細データの取得
            $arrRet = $this->lfGetOrderDetail($order_id);
            $arrOrderDetail = SC_Utils_Ex::sfSwapArray($arrRet);
            $arrData = array_merge($arrOrder, $arrOrderDetail);
        }
        return $arrData;
    }

受注完了メール

受注完了メールにも選択したギフト包装の種類と価格を載せる。

———————————————————–

小 計 ¥ 3,021 (うち消費税 ¥144)

値引き ¥ 1,195

送 料 ¥ 1,000

手数料 ¥ 300

ギフト包装:包装+リボン ¥ 200

===============================================================

合 計 ¥ 3,703

===============================================================

PCサイト用受注完了メールテンプレートの修正

/data/Smarty/templates/default/mail_templates/order_mail.tpl

L70あたり。

ギフト包装:<!–{$arrOrder.gift_type}–> ¥ <!–{$arrOrder.gift_price|number_format|default:0}–>

モバイルサイト用受注完了メールテンプレートの修正

/data/Smarty/templates/default/mobile/mail_templates/order_mail.tpl

L54(一番最後)に。

ギフト包装:<!–{$arrOrder.gift_type}–> ¥ <!–{$arrOrder.gift_price|number_format|default:0}–>

受注完了メール送信ロジックの拡張

/data/class_extends/helper_extends/SC_Helper_Mail_EX.php

class SC_Helper_Mail_Ex extends SC_Helper_Mail {
(この間にコードを追加。)
}

SC_Helper_Mail.phpのCLASSからソースをコピーしてきてSC_Helper_Mail_EX.php内で編集している。

    function SC_Helper_Mail_Ex() {
        parent::SC_Helper_Mail();
        $masterData = new SC_DB_MasterData_Ex();
        $this->arrGift = $masterData->getMasterData( “mtb_gift”,
                                array( “id”, “name”, “rank” ) );
    }

 

    /* 受注完了メール送信 */
    function sfSendOrderMail($order_id, $template_id, $subject = “”, $header = “”, $footer = “”, $send = true) {

        $objPage = new LC_Page();
        $objSiteInfo = new SC_SiteInfo();
        $arrInfo = $objSiteInfo->data;
        $objPage->arrInfo = $arrInfo;

        $objQuery = new SC_Query();

        if($subject == “” && $header == “” && $footer == “”) {
            // メールテンプレート情報の取得
            $where = “template_id = ?”;
            $arrRet = $objQuery->select(“subject, header, footer”, “dtb_mailtemplate”, $where, array(’1′));
            $objPage->tpl_header = $arrRet[0]['header'];
            $objPage->tpl_footer = $arrRet[0]['footer'];
            $tmp_subject = $arrRet[0]['subject'];
        } else {
            $objPage->tpl_header = $header;
            $objPage->tpl_footer = $footer;
            $tmp_subject = $subject;
        }

        // 受注情報の取得
        $where = “order_id = ?”;
        $arrRet = $objQuery->select(“*”, “dtb_order”, $where, array($order_id));
        $arrOrder = $arrRet[0];
        $arrOrderDetail = $objQuery->select(“*”, “dtb_order_detail”, $where, array($order_id));

        $objPage->Message_tmp = $arrOrder['message'];

        // 顧客情報の取得
        $customer_id = $arrOrder['customer_id'];
        $arrRet = $objQuery->select(“point”, “dtb_customer”, “customer_id = ?”, array($customer_id));
        $arrCustomer = isset($arrRet[0]) ? $arrRet[0] : “”;

        $objPage->arrCustomer = $arrCustomer;
        $objPage->arrOrder = $arrOrder;

        //その他決済情報
        if($arrOrder['memo02'] != “”) {
            $arrOther = unserialize($arrOrder['memo02']);

            foreach($arrOther as $other_key => $other_val){
                if(SC_Utils_Ex::sfTrim($other_val["value"]) == “”){
                    $arrOther[$other_key]["value"] = “”;
                }
            }

            $objPage->arrOther = $arrOther;
        }

        // 都道府県変換
        $objPage->arrOrder['deliv_pref'] = $this->arrPref[$objPage->arrOrder['deliv_pref']];

        // ギフト包装変換
        $objPage->arrOrder['gift_type'] = $this->arrGift[$arrOrder['memo09']];
        $objPage->arrOrder['gift_price'] = $arrOrder['memo10'];

        $objPage->arrOrderDetail = $arrOrderDetail;

        $objCustomer = new SC_Customer();
        $objPage->tpl_user_point = $objCustomer->getValue(‘point’);

        $objMailView = new SC_SiteView();
        // メール本文の取得
        $objMailView->assignobj($objPage);
        $body = $objMailView->fetch($this->arrMAILTPLPATH[$template_id]);

        // メール送信処理
        $objSendMail = new SC_SendMail_Ex();
        $bcc = $arrInfo['email01'];
        $from = $arrInfo['email03'];
        $error = $arrInfo['email04'];

        $tosubject = $this->sfMakeSubject($objQuery, $objMailView,
                                             $objPage, $tmp_subject);

        $objSendMail->setItem(”, $tosubject, $body, $from, $arrInfo['shop_name'], $from, $error, $error, $bcc);
        $objSendMail->setTo($arrOrder["order_email"], $arrOrder["order_name01"] . ” “. $arrOrder["order_name02"] .” 様”);
        // 送信フラグ:trueの場合は、送信する。
        if($send) {
            if ($objSendMail->sendMail()) {
                $this->sfSaveMailHistory($order_id, $template_id, $tosubject, $body);
            }
        }

        return $objSendMail;
    }

    // テンプレートを使用したメールの送信
    function sfSendTplMail($to, $subject, $tplpath, &$objPage) {
        $objMailView = new SC_SiteView();
        $objSiteInfo = new SC_SiteInfo();
        $arrInfo = $objSiteInfo->data;
        // メール本文の取得
        $objPage->tpl_shopname=$arrInfo['shop_name'];
        $objPage->tpl_infoemail = $arrInfo['email02'];
        $objMailView->assignobj($objPage);
        $body = $objMailView->fetch($tplpath);
        // メール送信処理
        $objSendMail = new SC_SendMail_Ex();
        $to = mb_encode_mimeheader($to);
        $bcc = $arrInfo['email01'];
        $from = $arrInfo['email03'];
        $error = $arrInfo['email04'];
        $objSendMail->setItem($to, $subject, $body, $from, $arrInfo['shop_name'], $from, $error, $error, $bcc);
        $objSendMail->sendMail();
    }

    // 通常のメール送信
    function sfSendMail($to, $subject, $body) {
        $objSiteInfo = new SC_SiteInfo();
        $arrInfo = $objSiteInfo->data;
        // メール送信処理
        $objSendMail = new SC_SendMail_Ex();
        $bcc = $arrInfo['email01'];
        $from = $arrInfo['email03'];
        $error = $arrInfo['email04'];
        $objSendMail->setItem($to, $subject, $body, $from, $arrInfo['shop_name'], $from, $error, $error, $bcc);
        $objSendMail->sendMail();
    }

    //件名にテンプレートを用いる
    function sfMakeSubject(&$objQuery, &$objMailView, &$objPage, $subject){

        $arrInfo = $objQuery->select(“*”,”dtb_baseinfo”);
        $arrInfo = $arrInfo[0];
        $objPage->tpl_shopname=$arrInfo['shop_name'];
        $objPage->tpl_infoemail=$subject;
        $objMailView->assignobj($objPage);
        $mailtitle = $objMailView->fetch(‘mail_templates/mail_title.tpl’);
        $ret = $mailtitle.$subject;
        return $ret;
    }

    // メール配信履歴への登録
    function sfSaveMailHistory($order_id, $template_id, $subject, $body) {
        $sqlval['subject'] = $subject;
        $sqlval['order_id'] = $order_id;
        $sqlval['template_id'] = $template_id;
        $sqlval['send_date'] = “Now()”;
        if (!isset($_SESSION['member_id'])) $_SESSION['member_id'] = “”;
        if($_SESSION['member_id'] != “”) {
            $sqlval['creator_id'] = $_SESSION['member_id'];
        } else {
            $sqlval['creator_id'] = ’0′;
        }
        $sqlval['mail_body'] = $body;

        $objQuery = new SC_Query();
        $objQuery->insert(“dtb_mail_history”, $sqlval);
    }

管理側受注管理

管理画面>受注管理>受注管理>受注履歴編集 で、ギフト包装の情報を見たり、変更できたりできるようにする。

有料に設定したid=1以上のギフト包装から、ギフトなしに変更(その逆も)して「計算結果の確認」や「この内容で変更する」を押したときに金額が変わることにも対応する。

管理画面>受注管理>ステータス管理 で受注番号を選択して出るポップアップのほうも対応する。

テンプレートの修正

※以下の2つは、管理画面用のテンプレートなので、カスタムテンプレートを使用している場合でも、defaultのテンプレートセットに変更を加えなければ、反映されないことに注意!

/data/Smarty/templates/default/admin/order/edit.tpl

L347あたりから。(手数料の下へ:表示させたい場所へ入れてOK)(ver.2.3.2の場合)

<tr bgcolor=”#ffffff” class=”fs12n”>
<td colspan=”5″ align=”right”>ギフト包装 : 
<!–{assign var=key value=”memo09″}–>
<span class=”red12″><!–{$arrErr[$key]}–></span>
<select name=”<!–{$key}–>” style=”<!–{$arrErr[$key]|sfGetErrorColor}–>”> 
<option value=”0″>ギフトなし</option>
<!–{html_options options=$arrGift selected=$arrForm[$key].value}–>
</td>
<td align=”right”><!–{$arrForm.memo10.value|number_format}–> 円</td>
</tr>

/data/Smarty/templates/default/admin/order/disp.tpl

L258あたりから。(手数料の下へ:表示させたい場所へ入れてOK)(ver.2.3.2の場合)

<tr bgcolor=”#ffffff” class=”fs12n”>
<td colspan=”4″ align=”right”>ギフト包装 :
<!–{if $arrDisp.memo09 != “” && $arrDisp.memo09 gt 0}–>
    <!–{$arrGift[$arrDisp.memo09]}–>
<!–{else}–>
    ギフトなし
<!–{/if}–>
</td>
<td align=”right”><!–{$arrDisp.memo10|number_format}–> 円</td>
</tr>

ページクラスの拡張

/data/class_extends/page_extends/admin/order/LC_Page_Admin_Order_Edit_Ex.php

init()、lfInitParam()、lfCheek()のコードを追加。L48あたりから。

    function init() {
        parent::init();
        $masterData = new SC_DB_MasterData_Ex();
        $this->arrGift = $masterData->getMasterData( “mtb_gift”,
                                array( “id”, “name”, “rank” ) );
    }

    function lfInitParam() {
        parent::lfInitParam();
        $this->objFormParam->addParam(“ギフト・のし”, “memo09″, INT_LEN, “n”, array(“EXIST_CHECK”, “MAX_LENGTH_CHECK”, “NUM_CHECK”), ’0′ );
        $this->objFormParam->addParam(“ギフト包装料金”, “memo10″ );
    }

    /* 計算処理 */
    function lfCheek($arrInfo) {
        $arrErr = parent::lfCheek( $arrInfo );
        $arrVal = $this->objFormParam->getHashArray();
       
        // ギフト包装料金の計算。合計とお支払い合計を計算しなおしす。0はギフト包装なしのこと。
        if ( intval( $_POST["memo09"] ) > 0 ) {
            // 合計
            $arrVal['total'] += GIFT_PRICE;
            // お支払い合計
            $arrVal['payment_total'] = $arrVal['total'] – ($arrVal['use_point'] * POINT_VALUE);
            $arrVal['memo10'] = GIFT_PRICE;
        } else {
            $arrVal['memo10'] = 0;
        }
       
       
        $this->objFormParam->setParam( $arrVal );
       
        return $arrErr;
       
    }

以上。

修正・アップロードするファイル一覧

  1.  /data/Smarty/templates/default/shopping/payment.tpl
  2.  /data/Smarty/templates/default/shopping/confirm.tpl
  3.  /data/Smarty/templates/default/mypage/history.tpl
  4.  /data/Smarty/templates/default/mail_templates/order_mail.tpl

 

  1.  /data/Smarty/templates/default/admin/order/edit.tpl
  2.  /data/Smarty/templates/default/admin/order/disp.tpl

 

  1. /data/Smarty/templates/default/mobile/shopping/deliv_date.tpl
  2.  /data/Smarty/templates/default/mobile/shopping/confirm.tpl
  3.  /data/Smarty/templates/default/mobile/mypage/history_detail.tpl
  4.  /data/Smarty/templates/default/mobile/mail_templates/order_mail.tpl

 

  1. /data/class_extends/page_extends/shopping/LC_Page_Shopping_Payment_Ex.php /data/class_extends/page_extends/shopping/LC_Page_Shopping_Confirm_Ex.php
  2.  /data/class_extends/page_extends/mypage/LC_Page_Mypage_History_Ex.php
  3.  /data/class_extends/page_extends/mypage/LC_Page_Mypage_HistoryDetail_Ex.php
  4.  /data/class_extends/page_extends/admin/order/LC_Page_Admin_Order_Edit_Ex.php

 

  1. /data/class_extends/helper_extends/SC_Helper_DB_Ex.php
  2.  /data/class_extends/helper_extends/SC_Helper_Mail_EX.php

参考:http://d.hatena.ne.jp/yuhei_kagaya/20080822

【EC-CUBE】メルマガの配信予約機能を使う(cron)

メルマガはデフォルトでは、配信設定したときに配信される。

これを、CRONを使って予約配信に変更し、30分ごとにメール配信予約ができるようにする。(*利用しているサーバがCRONによるJOBの予約に対応していること。)

その1)サーバのコンパネなどで下記コマンドのCRON設定を行う。

0,30 * * * * cd /(ECCUBEへのパス=/data/install.phpで確認すると良い)/html/admin/mail/; /usr/local/php/bin/php -f /(ECCUBEへのパス=/data/install.phpで確認すると良い)/html/admin/mail/sendmail.php 2>&1 > /dev/null

ちなみにcPanelの場合は、CRON設定画面でAdvanced(Unix Style)をクリック→
1つ目のフォーム:*/30
2つ目のフォーム:*
3つ目のフォーム:*
4つ目のフォーム:*
5つ目のフォーム**
6つ目のフォーム*cd /(ECCUBEへのパス=/data/install.phpで確認すると良い)/html/admin/mail/; /usr/local/php/bin/php -f /(ECCUBEへのパス=/data/install.phpで確認すると良い)/html/admin/mail/sendmail.php 2>&1 > /dev/null
を入力。

/usr/local/php/bin/phpは、/usr/bin/phpの場合もあるので、サーバのパスを確認すること。
Add Cronjobボタンをクリックして登録。上のフォームには、CRONが実行されたときに実行結果を送りたい管理者のメアドを入力しておく。

その2)EC-CUBE設定を行う。

管理画面→システム設定→パラメータ設定で、
[MELMAGA_BATCH_MODE]のパラメータを「false」から「true」へ変更。

管理画面→メルマガ管理でメールの配信を設定していくと、途中で予約配信の時間指定ができるようになっているので、30分単位で時間を入れて予約。毎時0分/30分に配信予約が入っているかの確認がCRONで送られてくる。

携帯メールの場合など設定を間違って夜中にお客さんのところにメールが届いた、といったミスが無いように、最初によくチェックしておくこと。

あとは、メルマガ配信予約で日時指定のときに、日につきの数値が入ってしまうバグがrので、/data/class/pages/admin/mail/LC_Page_Admin_Mail.phpの
292行目あたり「$this->arrNowDate['day'] = isset($_POST['send_day']) ? $_POST['send_month'] : “”;」となってしまっているのを、「$this->arrNowDate['day'] = isset($_POST['send_day']) ? $_POST['send_day'] : “”;」と修正する。

【EC-CUBE】商品一覧ページの商品の並べ替え降順を追加する

一覧ページの並べ替えリンクで、価格順に昇順だけでなく降順を追加する。
新着順も同様に変更可能。

その1)/data/Smarty/templates/default/list.tplに降順並べ替え用のリンクを追加

L69あたりから(ver.2.3.2例)のソースに価格降順用のソースを追記。「価格順」のソースをコピペして編集すればOK。

 <!–件数ここから–>
  <!–{if $tpl_linemax > 0}–>
  <ul class=”pagenumberarea”>
    <li class=”left”><span class=”pagenumber”><!–{$tpl_linemax}–></span>件の商品がございます。</li>
    <li class=”center”><!–{$tpl_strnavi}–></li>
    <li class=”right”><!–{if $orderby != ‘price’}–>
        <a href=”javascript:fnModeSubmit(”, ‘orderby’, ‘price’)”>価格順</a>
    <!–{else}–>
        <strong>価格順</strong>
    <!–{/if}–>&nbsp;
  <!–{if $orderby != ‘price2′}–>
        <a href=”javascript:fnModeSubmit(”, ‘orderby’, ‘price2′)”>価格降順</a>
    <!–{else}–>
        <strong>価格降順</strong>
    <!–{/if}–>&nbsp;
    <!–{if $orderby != “date”}–>
        <a href=”javascript:fnModeSubmit(”, ‘orderby’, ‘date’)”>新着順</a>
    <!–{else}–>
        <strong>新着順</strong>
    <!–{/if}–>
    </li>
  </ul><!–件数ここまで–>
  <!–{else}–>
    <!–{include file=”frontparts/search_zero.tpl”}–>
  <!–{/if}–>

その2)/data/class/pages/products/LC_Page_Products_List.phpに価格降順用のソースを追記。

こちらも同様に、上の「価格順」のソースをコピペして編集すればOK。

L393あたりから

        //価格順
        case ‘price’:
            $col = “DISTINCT price02_min, product_id, product_code_min, product_code_max,”
                . ” name, comment1, comment2, comment3,”
                . ” main_list_comment, main_image, main_list_image,”
                . ” price01_min, price01_max, price02_max,”
                . ” stock_min, stock_max, stock_unlimited_min, stock_unlimited_max,”
                . ” point_rate, sale_limit, sale_unlimited, deliv_date_id, deliv_fee,”
                . ” status, product_flag, create_date, del_flg”;
            $from = “vw_products_allclass AS T1″;
            $order = “price02_min, product_id”;
            break;

というソースがあるので、その下にコピーして下記のように編集。

        //価格順
        case ‘price2′:
            $col = “DISTINCT price02_min, product_id, product_code_min, product_code_max,”
                . ” name, comment1, comment2, comment3,”
                . ” main_list_comment, main_image, main_list_image,”
                . ” price01_min, price01_max, price02_max,”
                . ” stock_min, stock_max, stock_unlimited_min, stock_unlimited_max,”
                . ” point_rate, sale_limit, sale_unlimited, deliv_date_id, deliv_fee,”
                . ” status, product_flag, create_date, del_flg”;
            $from = “vw_products_allclass AS T1″;
            $order = “price02_min DESC, product_id”;
            break;

これで、追加OK。新着順を古いものから並べたいときは、同様の手順でその下の「新着順」のコードをコピペして、一番下の「$order = “create_date DESC, product_id”;」を「$order = “create_date, product_id”;」(DESCを削除)とすればよい。

【EC-CUBE】データベース内の文字化け対策

DBを作ったら、先にphpMyAdminでDBに接続。

上のタブで、SQLを開き、まずは、

status

または、

show variables like “char%”;

と打ち込んで、現在の文字コードを確認。

サーバの設定にあたる「character_set_server」以外をUTF8に揃える。

ので、

set names utf8;
または、
alter database 〜DB名 character set utf8; (←たぶんこっち。)

で変更。確認して変更されていればOK。

これで変更できない場合は、phpMyAdminのトップページなどから、「照合順序」で変えればいいかと。

character_set_serverは、サーバの設定なので、個別には変更できないが、専用サーバなどであれば、my.conf等で変更可能。

my.cnfの[mysqld]のところにdefault-character-set=utf8と書いておけばOK。

2.3.2以前の場合は、それだけでは、システム動作時に文字化けに戻ってしまうので、

data/class/SC_DbConn.php

L64~
$this->conn = $objDbConn; 
の手前に、

if (DB_TYPE == 'mysql') {
$objDbConn->query('SET NAMES utf8');
}

を追加。(参考:http://svn.ec-cube.net/open_trac/changeset/17559)この場合、my.cnfの設定は必要ない。

【EC-CUBE】新着商品をブロックで表示する

1)まずはオススメ商品のPHPソース3つをコピーして新着商品用にファイル名変更。

  • /data/class/pages/frontparts/bloc/LC_Page_FrontParts_Bloc_Best5.php
  • /data/class_extends/page_extends/frontparts/bloc/LC_Page_FrontParts_Bloc_Best5_Ex.php
  • /frontparts/bloc/best5.php

をそれぞれコピーし、Best5のところをNewに変更する。

  • /data/class/pages/frontparts/bloc/LC_Page_FrontParts_Bloc_New.php
  • /data/class_extends/page_extends/frontparts/bloc/LC_Page_FrontParts_Bloc_New_Ex.php
  • /frontparts/bloc/new.php

2)PHPソースの中の変数などBest5→Newへbest5→newへ置き換えする。(数箇所ある)

3)LC_Page_FrontParts_Bloc_New.phpのソースを変更。(Ver.2.3RC1の場合L55~)

    function process() {

        if (defined(“MOBILE_SITE”) && MOBILE_SITE) {
            $objView = new SC_MobileView();
        } else {
            $objView = new SC_SiteView();
        }
        $objSiteInfo = $objView->objSiteInfo;

~(中略:この中身を下記ソースに入れ替え)

        $objView->display($this->tpl_mainpage);
    }

———-(モバイルについて記載している↓この手前まで)
    /**
     * モバイルページを初期化する.
———-

  function process() {
if (defined(“MOBILE_SITE”) && MOBILE_SITE) {
$objView = new SC_MobileView();
} else {
$objView = new SC_SiteView();
}
$objSiteInfo = $objView->objSiteInfo;

// 基本情報を渡す
$objSiteInfo = new SC_SiteInfo();
$this->arrInfo = $objSiteInfo->data;
$objQuery = new SC_Query();

//検索したい商品のステータスを設定
//NEW→1, 残りわずか→2, ポイント2倍→3, オススメ→4, 限定品→5
$productFlag = 1;

//検索する商品のステータスをランダムに決定し、表示させたい場合は以下のコメントを外してください。
//$id_count = $objQuery->count(mtb_status);
//$productFlag = rand(1,$id_count);

$this->statusName =$objQuery->get(“mtb_status_image”, “name”, “id={$productFlag}”);

//表示する商品の件数
$listCount = 8;

$ret = “”;
$arrTmp[$productFlag] = “1″;

for($i = 1; $i <= $productFlag; $i++) {
if($arrTmp[$i] == “1″) {
$ret.= “1″;
} else {
$ret.= “_”;
}
}

if($ret != “”) {
$ret.= “%”;
}
//$col = “dtb_products.product_id, dtb_products.name, dtb_products.main_image,
// MIN(dtb_products_class.price02) AS price02_min, MAX(dtb_products_class.price02) AS price02_max”;
//$from = “dtb_products INNER JOIN dtb_products_class using(product_id)”;
//$where = “product_flag LIKE \”{$ret}\”";
//$groupby = “product_id”;
//$this->groupby=$objQuery->setgroupby($groupby);
//商品の表示はupdate_dateが新しい順
//$order = “dtb_products.update_date DESC”;
//$this->order=$objQuery->setorder($order);

$col = “DISTINCT price02_min, product_id, price02_max, main_list_image, status, product_flag, name”;
$from = “vw_products_allclass AS T1″;
$where = “del_flg = 0 AND status = 1 AND product_flag LIKE ‘{$ret}’”;
//商品の表示はproduct_id逆順
$order = “product_id DESC”;
$this->order=$objQuery->setorder($order);

$arrFlagList = $objQuery->select($col, $from, $where);

//商品の表示をランダムに抽出する場合は以下のコメントを外してください。
//srand((double)microtime()*1000000); //乱数生成器を初期化
//shuffle($arrFlagList);

$this->arrFlagProducts = array_slice($arrFlagList, 0, $listCount);
//この変数名をテンプレの値の呼び出しに使うので注意。

$objSubView = new SC_SiteView();
$objSubView->assignobj($this);
$objSubView->display($this->tpl_mainpage);
}

元のソースの最後のほうの商品検索functionは不要なので、削除。

4)上記の3つのファイルをアップロード。

5)新着商品用のブロックを作り、DBを修正する。

まず、管理画面で「デザイン管理」→「ブロック編集」でブロック名「新着商品表示」/ファイル名「new(.tpl)」を作成する。
内容は、おすすめ商品用ブロック(best5.tpl)をコピーして保存。

phpMyAdminでデータベースを開いて、「dtb_bloc」テーブルの中を見ると、新商品用ブロックのデータ、NEWが追加されているので、その中の、php_path(最初はnullとなっている)に「frontparts/bloc/new.php」と値をセット。

各ファイルの中で変数名がEC-CUBEのバージョンアップによって変更になったりすることがある。そのときは、BEST5のソースを参考にして、適宜調整するとよい。

例えば、$arrBest5は→$arrFlagProductsとなる。

これでOK。ブロックのレイアウトは表示したいように適宜変更。

参考:http://xoops.ec-cube.net/modules/newbb/viewtopic.php?viewmode=flat&order=ASC&topic_id=1276&forum=6

【EC-CUBE】ヘッダーにログインやかごの中ブロックを表示するには

ヘッダーを編集して、

「ログイン」を表示したい場合

<!--{include_php file=`$smarty.const.HTML_PATH`frontparts/bloc/login.php}-->

「商品検索」を表示したい場合

<!--{include_php file=`$smarty.const.HTML_PATH`frontparts/bloc/search_products.php}-->

「かごの中」を表示したい場合

<!--{include_php file=`$smarty.const.HTML_PATH`frontparts/bloc/cart.php}-->

をそれぞれヘッダーのソースに追加する。(ver.2.3RC1にて動作検証)

フッターは未検証だが、多分同様にすれば可能。

【EC-CUBE】カートの商品表示順の降・昇順を入れ替えて表示する

/data/Smarty/templates/default/cart/index.tpl

の下記の記述(Ver.2.3Rc1の場合、L71)に

<!–{section name=cnt loop=$arrProductsClass}–>

↓このように「step=-1」を追加。

<!–{section name=cnt loop=$arrProductsClass step=-1}–>

これだけ。

【EC-CUBE】モバイルでのポイント使用が出来るように改造する

ロジックは、あるから、テンプレの変更で対応できる。

1)/data/Smarty/templates/default/mobile/shopping/deliv_date.tpl

の33~35行目を

<!–{if $tpl_login == 1}–>
<!–<input type=”hidden” name=”point_check” value=”2″>–>
<!–{/if}–>

↓このように変更。

<!–{if $tpl_login == 1}–>
■ポイント利用<br />
現在の所持ポイントは「<!–{$tpl_user_point|default:0}–> pt」です。<br />
所持ポイント以上のポイントはご利用いただけません。<br />
<input type=”hidden” name=”point_check” value=”1″ />
<input type=”text” name=”use_point” istyle=”4″ />
<!–{/if}–>

2)/data/Smarty/templates/default/mobile/shopping/confirm.tpl

の72行目に以下を挿入。

【購入金額】<br>
商品合計:<!–{$tpl_total_pretax|number_format}–><br>
送料:<!–{$arrData.deliv_fee|number_format}–><br>
<!–{if $arrData.charge > 0}–>手数料:<!–{$arrData.charge|number_format}–><br><!–{/if}–>
(ここへコードを追加。)
合計:<!–{$arrData.payment_total|number_format}–><br>
(内消費税:<!–{$arrData.tax|number_format}–>)<br>

↓このように。

【購入金額】<br>
商品合計:<!–{$tpl_total_pretax|number_format}–><br>
送料:<!–{$arrData.deliv_fee|number_format}–><br>
<!–{if $arrData.charge > 0}–>手数料:<!–{$arrData.charge|number_format}–><br><!–{/if}–>
<!–{assign var=discount value=`$arrData.use_point*$smarty.const.POINT_VALUE`}–>-<!–{$discount|number_format|default:0}–>円
合計:<!–{$arrData.payment_total|number_format}–><br>
(内消費税:<!–{$arrData.tax|number_format}–>)<br>

【EC-CUBE】現在のページのURLを取得してテンプレートで(QRコードを)表示する。

ページのQRコードを動的に生成させる場合などに、現在のページそのもののURLを取得してテンプレートへ出力するには、PHPでURLを取得して、変数を定義しておく→tplファイルで、その変数を表示、というやり方も使える。

要は、

http://bton.papalabs.com/?p=355

http://bton.papalabs.com/?p=358

↑この記事の複合技。

先の記事は、EC-CUBEでプロダクトやカテゴリの変数を情報として使う前提でコードを組んでいるので、その他のページには使えない。でも、こちらのやり方であれば、その他のシステムにも応用が利く。但し、一覧ページの場合は、そのページそのものというのは、一覧のページということになるから、「一覧ページで各商品ページのURLをQRコードで表示したい」という場合は、先のやり方を使う。

1)現在のページURLを取得するPHPコードを保存する。

下記のコードを「urlget.php」という名称で作成し、EC-CUBEのルートディレクトリへ保存。(別に変えてもかまわない。)

<?php

$thisURL=’http://’.htmlspecialchars($HTTP_SERVER_VARS['HTTP_HOST'],ENT_QUOTES).htmlspecialchars($HTTP_SERVER_VARS['REQUEST_URI'],ENT_QUOTES);

define(’CONFIG_THIS_URL’,$thisURL);  
?>

2)作成した「urlget.php」を読み込む。

/require.php

の適当な位置(Ver.2.3RC1の場合、L27とかが分かりやすい。)に

require_once($require_php_dir . “/urlget.php”);

と追記し、「urlget.php」を呼び出す。

3)テンプレートに表示用のコードを追加。

そのページそのもののQRコードを表示させたいテンプレートに、

<img src=”<!–{$smarty.const.SITE_URL}–>php/qr_img.php?d=<!–{$smarty.const.CONFIG_THIS_URL}–>&e=M&s=3&t=j”>

または、

<img src=”<!–{$smarty.const.URL_DIR}–>php/qr_img.php?d=<!–{$smarty.const.CONFIG_THIS_URL}–>&e=M&s=3&t=j”>

と記載する。(QRコード表示用のPHPへのパスの表示が変わるだけで結果は同じなので、どっちでもOK。)

qr_img.phpへのパスと格納ディレクトリに矛盾がないか確認のこと。(アップロードしたディレクトリ構造によって上記パスは変わる)

【EC-CUBE】商品一覧の表示順(昇順・降順)の変更・追加

商品一覧ページの一覧上下に表示されているソートリンクを追加(または変更)して、降順・昇順の並べ替えボタンを作ることができる。

例えば、
「価格:高い順 安い順 新しい順 古い順
に並べ替えというようなことが可能。

1)/data/class/pages/products/LC_Page_Products_List.php を編集。

        //表示順序
        switch($orderby) {

という記述を探します。(Ver.2.3RC1の場合、L387あたり。)

その下の、

「case ‘ ○○ ‘:」

という部分が、それぞれのソートのルールを決めている部分。

この中の、「$order =” ○○ “;」というところがソートの指定。ここに、ソートに使用したい項目を入れる。優先順も。降順にしたい場合は、項目の後に半角スペースを入れて、「disc」と記述。

仮に、価格降順(高いほうから安いほうへ)のソートルールを作るのであれば、

        case ‘price’:
            $col = “DISTINCT price02_min, product_id, product_code_min, product_code_max,”
                . ” name, comment1, comment2, comment3,”
                . ” main_list_comment, main_image, main_list_image,”
                . ” price01_min, price01_max, price02_max,”
                . ” stock_min, stock_max, stock_unlimited_min, stock_unlimited_max,”
                . ” point_rate, sale_limit, sale_unlimited, deliv_date_id, deliv_fee,”
                . ” status, product_flag, create_date, del_flg”;
            $from = “vw_products_allclass AS T1″;
            $order = “price02_min, product_id”;
            break;

をコピーして、「case ‘price2′:」などとして、「$order = “price02_min, product_id”;」→「$order = “price02_min disc, product_id”;」とすればよい。

2)/data/Smarty/templates/default/list.tpl テンプレートにソーとリンクを追加表示させる。

L69行目以下の適当な場所/L188行目以下の適当な場所に表示リンクを追加(または修正)する。

先の例で、価格降順のリンクを追加する場合としたら、

<!–{if $orderby != ‘price2‘}–>
        <a href=”javascript:fnModeSubmit(”, ‘orderby’, ‘price2‘)”>価格順</a>
    <!–{else}–>
        <strong>価格順</strong>
    <!–{/if}–>&nbsp;

こういう形のコードを追加し、「価格順」という文字を「価格昇順」と変更すれば、価格のソートは、高いほうからも安いほうからも並べ替えできるようになる。

【EC-CUBE】お問い合わせフォームに項目追加

例として「お問い合わせ」のお客様情報入力欄に「会社名」欄を追加する

1)\data\class\pages\contact\LC_Page_Contact.php を修正。

  1. 「フォーム値変換用カラム」部分の「お名前」の前に会社名分を追加。 (Ver.2.3Rc1の場合、L79あたり)
    array( “column” => “cname01″, “convert” => “aKV” ),
  2. 「エラーチェック処理部」部分の「お名前」の前に会社名分を追加。 (Ver.2.3Rc1の場合、L188あたり)
    $objErr->doFunc(array(“会社名”, “cname01″, MTEXT_LEN), array(“SPTAB_CHECK” ,”MAX_LENGTH_CHECK”));

2)\data\Smarty\templates\default\contact\index.tpl を修正。 

会社名入力枠を「お名前」の前に追加する。 (Ver.2.3Rc1の場合、L37あたり)

<tr>
<th>会社名</th>
<td>
<input type=”text”
class=”box380″
name=”cname01″
value=”<!–{$cname01|default:$arrData.cname01|escape}–>”
maxlength=”<!–{$smarty.const.STEXT_LEN}–>”
style=”<!–{$arrErr.cname01|sfGetErrorColor}–>” /> 
</td>
</tr>

3)\data\Smarty\templates\default\contact\confirm.tpl

会社名表示枠を「お名前」の前に追加する。 (Ver.2.3Rc1の場合、L38あたり)

<tr>
<th>会社名</th>
<td><!–{$arrForm.cname01|escape}–></td>
</tr>

4)\data\Smarty\templates\default\mail_templates\contact_mail.tpl

会社名を「お名前」の前に追加。 (Ver.2.3Rc1の場合、L42あたり)

■会社名:<!–{$arrForm.cname01}–>

【EC-CUBE】SEO対策の続き。GOOGLE MAP用サイトマップ内のURLも変更。

EC-CUBEのサイト内URLをSEO用に静的HTML化した。で、今度は、GOOGLEサイトマップ用のXMLファイル内のリンクも同じように静的HTML化する。

※これは、自サイトの記事(http://bton.papalabs.com/?p=325)で、既に一覧や詳細ページなど全体的な静的HTML化の設定が出来ていることを前提とする。

/data/class/pages/LC_Page_Sitemap.php

を修正。

(Ver.2.3Rc1の場合)
L240

            $page = array(“url” => SITE_URL . sprintf(“%sproducts/list.php?category_id=%d”, $mobile, $result[$i]['category_id']));

↓↓↓下記のように変更。

            $page = array(“url” => SITE_URL . sprintf(“%sproducts/list%d.html”, $mobile, $result[$i]['category_id']));

L264

            $page = array(“url” => SITE_URL. sprintf(“%sproducts/detail.php?product_id=%d”, $mobile, $result[$i]['product_id']),
                          “update_date” => $result[$i]['update_date']);

↓↓↓下記のように変更。

            $page = array(“url” => SITE_URL. sprintf(“%sproducts/detail%d.html”, $mobile, $result[$i]['product_id']),
                          “update_date” => $result[$i]['update_date']);

保護中: 【EC-CUBE】商品ページへ動的にQRコードを生成する

この投稿はパスワードで保護されています。表示するにはパスワードを入力してください:


【EC-CUBE】各種設定

基本的には、管理画面のシステム設定内、パラメータ設定で、値を変えればよい。

パラメータ設定で変わらないとき、該当するファイルは、

/data/mtb_constants_init.php
/data/cache/mtb_constants.php (キャッシュファイル)

を修正すればOK。さらに、phpMyAdminでDBの、mtb_constantsテーブルを探し、該当するフィールドを直接編集すればOK。

  1. メルマガの配信予約をしたいときは、この中の値、MELMAGA_BATCH_MODEをtrureに設定すると配信設定が日時予約画面に変わる。(cronが必要)
  2. 仮会員登録制にする場合は、CUSTOMER_CONFIRM_MAILをtrueに設定する。
  3. カスタマイズ中にエラーの原因を特定したいときは、DEBUG_MODEをtrueにすると、エラーメッセージが表示される。

【EC-CUBE】パンくずリストの実装

VER.2.3RC1の場合。

1)/data/class_extends/helper_extends/SC_Helper_DB_Ex.php の編集。

「class SC_Helper_DB_Ex extends SC_Helper_DB」の中にコードを仕込む。
37行目(”{“と”}”の間)に以下を追加。

 
function sfGetTopicPath($category_id){
// 商品が属するカテゴリIDを縦に取得
$objQuery = new SC_Query();
$arrCatID = $this->sfGetParents($objQuery, “dtb_category”, “parent_category_id”, “category_id”, $category_id);
$TopicPath = ” > “;

// カテゴリー名称を取得する
foreach($arrCatID as $key => $val){
$sql = “SELECT category_name FROM dtb_category WHERE category_id = ?”;
$arrVal = array($val);
$CatName = $objQuery->getOne($sql,$arrVal);
if( $val != $category_id){
$TopicPath .= ‘‘ . $CatName . ‘ > ‘;
}else{
$TopicPath .= $CatName;
}
}

return $TopicPath;
}
function sfGetTopicPath2($category_id){
// 商品が属するカテゴリIDを縦に取得
$objQuery = new SC_Query();
$arrCatID = $this->sfGetParents($objQuery, “dtb_category”, “parent_category_id”, “category_id”, $category_id);
$TopicPath = ” > “;

// カテゴリー名称を取得する
foreach($arrCatID as $key => $val){
$sql = “SELECT category_name FROM dtb_category WHERE category_id = ?”;
$arrVal = array($val);
$CatName = $objQuery->getOne($sql,$arrVal);
$TopicPath .= ‘‘ . $CatName . ‘ > ‘;
}
return $TopicPath;
}

2)/data/class/pages/products/LC_Page_Products_List.php の編集。 (L112に2行追加。)

        // タイトル編集
        $tpl_subtitle = “”;
        if ($_GET['mode'] == ‘search’) {
            $tpl_subtitle = “検索結果”;
        } elseif (empty($arrCategory_id[0])) {
            $tpl_subtitle = “全商品”;
        } else {
            $arrFirstCat = $objDb->sfGetFirstCat($arrCategory_id[0]);
            $tpl_subtitle = $arrFirstCat['name'];

            $TopicPath = $objDb->sfGetTopicPath($arrCategory_id[0]); ←追加
            $this->tpl_topicpath = $TopicPath; ←追加

        }

 3)/data/class/pages/products/LC_Page_Products_Detail.php の編集。 (L229に2行追加。)

        // サブタイトルを取得
        $arrCategory_id = $objDb->sfGetCategoryId($arrRet[0]['product_id'], $status);
        $arrFirstCat = $objDb->sfGetFirstCat($arrCategory_id[0]);
        $this->tpl_subtitle = $arrFirstCat['name'];

        $arrTopicPath = $objDb->sfGetTopicPath2($arrCategory_id[0]); ←追加
        $this->tpl_topicpath = $arrTopicPath; ←追加

        // 関連カテゴリを取得
        $this->arrRelativeCat = $objDb->sfGetMultiCatTree($tmp_id);

4)パンくずリスト用新規ブロックの追加。

デザイン管理→ブロック編集 で新規ブロックをつくり、下記コードを適当な名前で保存。(ブロック名:「パンくずリスト」、ファイル名:「topicpath」で保存。でも、分かれば、なんでもいい。)

<!–{if $tpl_topicpath != “”}–>
<a href=”<!–{$smarty.const.SITE_URL}–>index.php”>TopPage</a>
<!–{$tpl_topicpath}–>
<!–{$arrProduct.name|escape}–>
<!–{/if}–>

デザイン管理→レイアウト編集 にパンくずリストのブロックが出来ているので、パンくずリストを実装したいページ(一覧ページや詳細ページ)の該当箇所にパンくずリストのブロックを設定すればOK。

参考:http://www.gnnk.net/20080113050103/

注意! 「カテゴリの説明やビジュアルを追加する」とアタる!
下記のやり方で、LC_Page_Products_List_Ex.phpを使用する場合、こちらのパンくず実装を先にやるか、LC_Page_Products_List_Ex.phpで実装しないと、マージされないので注意!すること。
http://www.eccube-school.jp/products/detail43.html

http://www.bton.net46.net/?p=313 (←こっちのほうは、_EXを使ってないので、同じファイルを上書きすることになるから問題ない。でも、本来は、_EXを使ったほうがいいので、_EXのファイルのほうで、パンくずを実装するってほうがいいのかも。メモメモ。)

【EC-CUBE】SEO対策。メタの記載内容を個別ページごとに入れ替える。

EC-CUBEでは、METAタグは、基本設定で一括して決められてしまう(現状仕様)が、商品の個別ページなどは、その商品向けにそれぞれ別途登録したいことも多い。

んで、個別のキーワードやディスクリプションを設定できるようにカスタマイズする。

1)/data/Smarty/templates/site_frame.tpl の<title>タグと、<description>タグと、<keyword>タグを置き換える。

  1. トップページ
    <title>ショップ名 | 基本設定:SEO管理で入力したトップページ用description</title>
    <description>基本設定:SEO管理で入力したトップページ用description</description>
    <keyword>基本設定:SEO管理で入力したトップページ用keyword</keyword>
  2. 商品一覧ページ(カテゴリ未選択時)
    <title>基本設定:SEO管理で入力した商品一覧用description | ショップ名</title>
    <description>基本設定:SEO管理で入力した商品一覧用description</description>
    <keyword>基本設定:SEO管理で入力した商品一覧用keyword</keyword>
  3. 商品一覧ページ(カテゴリ選択時)
    <title>カテゴリ名 | ショップ名</title>
    <description>基本設定:SEO管理で入力した商品一覧ページ用description</description>
    <keyword>基本設定:SEO管理で入力した商品一覧ページ用keyword</keyword>
  4. 商品詳細ページ
    <title>商品名 | ショップ名</title>
    <description>商品登録の「一覧-メインコメント」 </description>
    <keyword>商品登録の「検索ワード」 </keyword>
  5. その他
    <title>ページ名 | ショップ名</title>
    <description>基本設定:SEO管理で入力したdescription</description>
    <keyword>基本設定:SEO管理で入力したkeyword</keyword>

「/data/Smarty/templates/site_frame.tpl」をFTPでダウンロードし、編集。
<title>、<meta name=”description”~ 、<meta name=”keywords”~ の3項目を削除。<meta name=”author” のみ残す。(ver.2.3rc1の場合、34行目あたりから)

<title><!–{$arrSiteInfo.shop_name|escape}–>/<!–{$tpl_title|escape}–></title> ←削除
<meta name=”author” content=”<!–{$arrPageLayout.author|escape}–>” />
<meta name=”description” content=”<!–{$arrPageLayout.description|escape}–>” /> ←削除
<meta name=”keywords” content=”<!–{$arrPageLayout.keyword|escape}–>” /> ←削除

TITLEタグを削除した場所に、下記のコードを追加。

<!–{assign var=top value=”`$smarty.const.URL_DIR`index.php”}–>
<!–{assign var=list value=”`$smarty.const.URL_DIR`products/list.php”}–>
<!–{assign var=detail value=”`$smarty.const.URL_DIR`products/detail.php”}–>

<!–{if $smarty.server.PHP_SELF==$top}–>
<!–トップページ–>
<title><!–{$arrSiteInfo.shop_name}–> | <!–{$arrPageLayout.description|escape}–></title>
<meta name=”description” content=”<!–{$arrPageLayout.description|escape}–>” />
<meta name=”keywords” content=”<!–{$arrPageLayout.keyword|escape}–>” />

<!–{elseif $smarty.server.PHP_SELF==$list}–>
<!–商品一覧ページ–>
<!–{if $tpl_subtitle != “全商品”}–>
<title><!–{$tpl_subtitle}–> | <!–{$arrSiteInfo.shop_name}–></title>
<!–{else}–>
<title><!–{$arrPageLayout.description|escape}–> | <!–{$arrSiteInfo.shop_name}–></title>
<!–{/if}–>
<meta name=”description” content=”<!–{$arrPageLayout.description|escape}–>” />
<meta name=”keywords” content=”<!–{$arrPageLayout.keyword|escape}–>” />

<!–{elseif $smarty.server.PHP_SELF==$detail}–>
<!–商品詳細ページ–>
<title><!–{$tpl_title|escape}–> | <!–{$arrSiteInfo.shop_name}–></title>
<meta name=”description” content=”<!–{$arrProduct.main_list_comment|escape|regex_replace:”/[\r\t\n]/”:”"}–>” />
<meta name=”keywords” content=”<!–{if $arrProduct.comment3}–><!–{$arrProduct.comment3|escape|regex_replace:”/[\r\t\n]/”:”"|regex_replace:”/、/”:”,”}–>
<!–{/if}–>” />

<!–{else}–>
<!–その他の場合–>
<title><!–{$tpl_title|escape}–> | <!–{$arrSiteInfo.shop_name}–></title>
<meta name=”description” content=”<!–{$arrPageLayout.description|escape}–>” />
<meta name=”keywords” content=”<!–{$arrPageLayout.keyword|escape}–>” />
<!–{/if}–>

 2)/data/class/db/dbfactory/SC_DB_DBFactory_MYSQL.phpを修正する。

“vw_products_allclass_detail” に main_list_commentを追記(mySQLの場合)。
PostgreSQLの場合は、データベースに記録されるようなので、データベース上でフィールドを追加する。

(ver.2.3rc1の場合、438行目あたりから)

“vw_products_allclass_detail” => ‘
    (SELECT product_id,price01_min,price01_max,price02_min,price02_max, stock_min,stock_max,stock_unlimited_min,stock_unlimited_max,del_flg, status,name,comment1,comment2,comment3,main_list_comment,deliv_fee, main_comment,main_image,main_large_image, sub_title1,sub_comment1, sub_image1,sub_large_image1,

    以下省略・・・(※「,」の後ろで半角スペースが入っているところは、実際は入れなくていい。ブログの表示用に便宜上いれてるだけ。)

これで、管理画面の基本情報のなかのSEO設定に入力した、全ページ共通のMETAやタイトルだけではなく、個別の商品情報の中で設定した検索用のキーワードや一覧用の商品説明も、各ページのMETA情報として追加されるようになった。

表示される内容を変えたい場合は、「/data/Smarty/templates/site_frame.tpl」のなかで、表示したい変数を埋め込むようにすればOK。

さらに、2.3バージョンでは、GOOGLE SITEMAP用にサイトマップを書き出せるようになっているので、こちらのサイトマップのURLも静的HTMLで書き出されるように編集しておく。

/data/class/pages/LC_Page_Sitemap.php

$page = array(“url” => SITE_URL . sprintf(“%sproducts/list.php?category_id=%d”, $mobile, $result[$i]['category_id']));

これを↓↓↓このように編集。(Ver.2.3Rc1の場合、240行目あたり)

$page = array(“url” => SITE_URL . sprintf(“%sproducts/list%d.html”, $mobile, $result[$i]['category_id']));

さらに、

$page = array(“url” => SITE_URL. sprintf(“%sproducts/detail.php?product_id=%d”, $mobile, $result[$i]['product_id']),

これを↓↓↓このように編集。(Ver.2.3Rc1の場合、264行目あたり)

$page = array(“url” => SITE_URL. sprintf(“%sproducts/detail%d.html”, $mobile, $result[$i]['product_id']),

【EC-CUBE】ページのURLを静的HTMLで表示するには。

SEOに有効な静的HTML表示にPHPページのURLを変換する。

1)/products/以下に「.htaccess」ファイルを設定する。
mod_rerwiteを利用するので、「.htaccess」ファイルに、下記のように記述して、FTPで/productsディレクトリにアップロードする。

RewriteBase /products ←これは、要らないサーバもある。
RewriteEngine on
RewriteRule ^detail([0-9]+).html+ products/detail.php?product_id=$1 [L]
RewriteRule ^list([0-9]+).html+ products/list.php?category_id=$1 [L]

http://www.ドメイン/products/detail.php?product_id=○○

というURLを

http://www.ドメイン/products/detail○○.html

と変換して、どちらのURLでアクセスしても、同じページが表示されるようにすることになる。
変換されるほうのURLの表示を変えたいときは、RewriteRuleの表記を変えればOK。

例えば、
RewriteRule detail\/([0-9]+)\/? products/detail.php?product_id=$1[L]
とすれば、「products/detail/○○」となる。

この時点で、
http://www.ドメイン/products/detail○○.html

でアクセスできていれば、ここまでの設定はOK。
もし、アクセスできなければ、サーバの設定を確認するなどで、対応。

2)EC-CUBEの管理画面で、システム管理メニューからパラメータを変更する。

半分より下あたりに「DETAIL_P_HTML」という文字列があるので探す。検索したほうが早い;

「DETAIL_P_HTML」の初期値で入っている、
『URL_DIR . “products/detail.php?product_id=”』 を
『URL_DIR . “products/detail”』 に書き換える。

3)テンプレ変更

/data/Smarty/templates/default/list.tpl
/data/Smarty/templates/default/bloc/best5.tpl
/data/Smarty/templates/default/bloc/category.tpl
/data/Smarty/templates/default/mypage/history.tpl

を変更するけれど、管理画面から変更できるので、確認しながらやるべし。
ローカルでファイルを修正してFTPでアップロードする場合は、アップロードしてから、デザイン管理→テンプレート設定の画面で、「この内容で登録する」ボタンをクリックして、テンプレを適用させること。(FTPアップロードしただけでは反映されない)

該当する「/products/detail.php?product_id=」の部分を、「details」に変え、その変数の後ろに「.html」を挿入し。DETAIL_P_HTMLが入っているところも同じように変更。さらに、「/products/list.php?category_id=」も。検索しながら良く見て変更すること。

デザイン管理→ページ詳細設定→「商品一覧ページ」を選択してコードを表示させ、修正。
DETAIL_P_HTMLのある場所を検索して、その後ろの変数の後に、「.html」を追加。3箇所ある。(ver.2.3rc1の場合、L97,L117,L130)

終わったら、「商品詳細ページ」も同様に修正。4箇所ある。(同じく、L324,L330,L349,L359)

<a href=”<!–{$smarty.const.DETAIL_P_HTML}–><!–{$arrProducts[cnt].product_id}–>.html“ ←追加。

「MYページ」はなぜか管理画面から変更できないので、後で直接ファイルを変更してFTPで上げる。

/data/Smarty/templates/default/mypage/history.php
(ver.2.3rc1の場合、L53)

<td><a href=”<!–{$smarty.const.URL_DIR}–>products/detail.php?product_id=<!–{$arrDisp.product_id[cnt]}–>”>

これを↓↓↓へ。

<td><a href=”<!–{$smarty.const.URL_DIR}–>products/detail<!–{$arrDisp.product_id[cnt]}–>.html”>

次に、管理画面のブロック編集へ。「カテゴリ」ブロックを開く。(ver.2.3rc1の場合、L46)

最後に、「オススメ商品」も。4箇所修正。(ver.2.3rc1の場合、L37,L42,L68,73)

<a href=”<!–{$smarty.const.URL_DIR}–>products/detail.php?product_id=<!–{$arrBestProducts[cnt].product_id}–>”>

これを↓↓↓へ。

<a href=”<!–{$smarty.const.URL_DIR}–>products/detail<!–{$arrBestProducts[cnt].product_id}–>.html”>

以上。その他に同様の修正が必要なところがあれば(バージョンアップなどで発生する可能性もあるし。)同じように修正する。

<a href=”<!–{$smarty.const.URL_DIR}–>products/list.php?category_id=<!–{$arrTree[cnt].category_id}–>”

これを↓↓↓へ。

<a href=”<!–{$smarty.const.URL_DIR}–>products/list<!–{$arrTree[cnt].category_id}–>.html”
 

さらに。

4)GOOGLEサイトマップ用のXMLサイトマップも静的HTMLで出力したい。

GOOGLEサイトマップ用のXMLサイトマップ作成機能についても、同じように、「.html」の拡張子で表示させたい。

/data/class/pages/LC_Page_Sitemap.php

の240行目。(Ver.2.3RC1の場合。)

            // :TODO: カテゴリの最終更新日を取得できるようにする
            $page = array(“url” => SITE_URL . sprintf(“%sproducts/list.php?category_id=%d”, $mobile, $result[$i]['category_id'])); ←これを変更。
            $arrRet[$i] = $page;

↓↓↓このように変更。

            // :TODO: カテゴリの最終更新日を取得できるようにする
            $page = array(“url” => SITE_URL . sprintf(“%sproducts/list%d.html“, $mobile, $result[$i]['category_id']));
            $arrRet[$i] = $page;

264行目も。

        for ($i = 0; $i < count($result); $i++) {
            $page = array(“url” => SITE_URL. sprintf(“%sproducts/detail.php?product_id=%d”, $mobile, $result[$i]['product_id']), ←これを変更。
                          “update_date” => $result[$i]['update_date']);

↓↓↓このように変更。

        for ($i = 0; $i < count($result); $i++) {
            $page = array(“url” => SITE_URL. sprintf(“%sproducts/detail%d.html“, $mobile, $result[$i]['product_id']),
                          “update_date” => $result[$i]['update_date']);

これで、GOOGLE用のXMLサイトマップもリンクは全て静的URLで書き出されます。

【EC-CUBE】カテゴリーごとのキャプションをつけるカスタマイズ

システムバージョン:2.3.0-rc1

その1)データベースのdtb_categoryテーブルに2つのフィールドを追加する
カテゴリーの情報が登録されているdtb_categoryテーブルに新しく2つのフィールドを追加する。

category_info(タイプ: text デフォルト: NULL 空の値:OK(NULL))
info_flg(タイプ: smallint デフォルト: 0 空の値:OK(NULL))

 ↓こんな風に追加して、

 ↓こうなっていればOK。

その2)「/data/Smarty/templates/default/admin/products/category.tpl」 を編集
管理画面のテンプレートにカテゴリの説明文を記述できる textarea と親カテゴリの説明文を引き継ぐかどうかのチェックボックスを追記。一番上のカテゴリの場合は親カテゴリは無い為、親カテゴリの説明文を引き継ぐかどうかのチェックボックスを表示しない。

128行目あたり(Ver.2.3の場合)に2行追加。

<input type=”text” name=”category_name” value=”<!–{$arrForm.category_name|escape}–>” size=”30″ class=”box30″ maxlength=”<!–{$smarty.const.STEXT_LEN}–>”/>
<input type=”submit” name=”button” value=”登録”/><span class=”red10″> (上限<!–{$smarty.const.STEXT_LEN}–>文字)</span>

↑この記述の下に、↓これを2行追加。

<textarea name=”category_info” cols=”80″ rows=”10″><!–{$arrForm.category_info|escape}–></textarea><br />

<!–{if $arrForm.level != “1″ && $arrForm.parent_category_id != “0″}–><input type=”checkbox” name=”info_flg” id=”info_flg” value=”1″<!–{if $arrForm.info_flg}–> checked=”checked”<!–{/if}–> /><label for=”info_flg” class=”fs10n”>親カテゴリの説明を引き継ぐ</label>  <!–{/if}–><span class=”red10″> (上限<!–{$smarty.const.LLTEXT_LEN}–>文字)</span>

その3)「/data/class/pages/admin/ products/LC_Page_Admin_Products_Category.php」に追記

110行目あたり(Ver.2.3の場合)。

// 編集項目のカテゴリ名をDBより取得する。
//$oquery = new SC_Query(); ←コメントアウト
$this->objQuery = new SC_Query();
$where = “category_id = ?”;

//$cat_name = $this->oquery->get(“dtb_category”, “category_name”, $where, array($_POST['category_id'])); ←コメントアウト
$col = “category_name, category_info, info_flg, level”;
$arrRet = $this->objQuery->select($col, “dtb_category”, $where, array($_POST['category_id']));

// 入力項目にカテゴリ名を入力する。
//$this->arrForm['category_name'] = $cat_name; ←コメントアウト
$this->arrForm['category_name'] = $arrRet[0]['category_name'];
$this->arrForm['category_info'] = $arrRet[0]['category_info'];
$this->arrForm['info_flg'] = $arrRet[0]['info_flg'];
$this->arrForm['level'] = $arrRet[0]['level'];
// POSTデータを引き継ぐ
$this->arrForm['category_id'] = $_POST['category_id'];

256行目あたり(Ver.2.3の場合)。

// 入力データを渡す。
$sqlval = $this->objFormParam->getHashArray();
$sqlval['create_date'] = “Now()”;
$sqlval['update_date'] = “Now()”;
$sqlval['creator_id'] = $_SESSION['member_id'];
$sqlval['parent_category_id'] = $parent_category_id;
$sqlval['rank'] = $rank;
$sqlval['level'] = $level;

//追記:親の設定を引き継ぐ時
if($sqlval['info_flg']) {
$sqlval['category_info'] = lfGetParentInfo($objQuery, $parent_category_id);
}

// INSERTの実行
$objQuery->insert(“dtb_category”, $sqlval);

$objQuery->commit(); // トランザクションの終了
}

// カテゴリの編集
function lfUpdateCat($category_id) {
$objQuery = new SC_Query();
// 入力データを渡す。
$sqlval = $this->objFormParam->getHashArray();
$sqlval['update_date'] = “Now()”;
$where = “category_id = ?”;

//追記:親の設定を引き継ぐ時
if($sqlval['info_flg']) {
$parent_category_id = $objQuery->get(“dtb_category”, “parent_category_id”, $where, array($category_id));
$sqlval['category_info'] = lfGetParentInfo($objQuery, $parent_category_id);
}
$objQuery->update(“dtb_category”, $sqlval, $where, array($category_id));
}

// カテゴリの取得
function lfGetCat($parent_category_id) {
$objQuery = new SC_Query();

if($parent_category_id == “”) {
$parent_category_id = ’0′;
}

$col = “category_id, category_name, level, rank”;
$where = “del_flg = 0 AND parent_category_id = ?”;
$objQuery->setoption(“ORDER BY rank DESC”);
$arrRet = $objQuery->select($col, “dtb_category”, $where, array($parent_category_id));
return $arrRet;
}

/* パラメータ情報の初期化 */
function lfInitParam() {
$this->objFormParam->addParam(“カテゴリ名”, “category_name”, STEXT_LEN, “KVa”, array(“EXIST_CHECK”,”SPTAB_CHECK”,”MAX_LENGTH_CHECK”));

$this->objFormParam->addParam(“カテゴリ情報”, “category_info”, LLTEXT_LEN, “KVa”, array(“SPTAB_CHECK”,”MAX_LENGTH_CHECK”));
$this->objFormParam->addParam(“引き継ぎ”, “info_flg”, INT_LEN, “n”, array(“MAX_LENGTH_CHECK”, “NUM_CHECK”));

} ←これ、注意!「}」は、追加していない。
/* 入力内容のチェック */
function lfCheckError($array)

コードの一番最後(Ver.2.3の場合)に追加。

// 追記:親のcategory_infoを取得する
function lfGetParentInfo($objQuery, $pid) {
$where = “category_id = ?”;
$parent_info = $objQuery->get(“dtb_category”, “category_info”, $where, array($pid));
return $parent_info;
}

その4)/data/class/pages/products/LC_Page_Products_List.php」に追記

115行目あたり(Ver.2.3の場合)。

// タイトル編集
$tpl_subtitle = “”;
if ($_GET['mode'] == ‘search’) {
$tpl_subtitle = “検索結果”;
} elseif (empty($arrCategory_id[0])) {
$tpl_subtitle = “全商品”;
} else {
$tpl_subtitle = $objDb->sfGetCatCombName($arrCategory_id[0]);
}

$objQuery = new SC_Query();
$this->category_info = $objQuery->get(“dtb_category”, “category_info”, “category_id = ?”, $arrCategory_id);
$count = $objQuery->count(“dtb_best_products”, “category_id = ?”, $arrCategory_id);

// 以下の条件でBEST商品を表示する
// ・BEST最大数の商品が登録されている。
// ・カテゴリIDがルートIDである。

その5)管理画面から商品一覧ページのメインを修正(list.tpl)

管理画面の「デザイン管理」→「ページ詳細設定」→「商品一覧ページ」で、任意の場所に以下のタグを挿入。

<!–{if $category_info}–><!–{$category_info}–><!–{/if}–>

参考:http://www.eccube-school.jp/products/detail43.html

注意! 「パンくずリストの実装」とアタる!
このやり方(http://www.eccube-school.jp/products/detail43.html)で、LC_Page_Products_List_Ex.phpを使用する場合、下記のパンくず実装を先にやるか、LC_Page_Products_List_Ex.phpで実装しないと、マージされないので注意!すること。
http://bton.papalabs.com/?p=340

この記事のほうは、_EXを使ってないので、同じファイルを上書きすることになるから問題ない。でも、本来は、_EXを使ったほうがいいので、_EXのファイルのほうで、パンくずを実装するってほうがいいのかも。

【EC-CUBE】インストールするときに階層変更が必要だ。

EC-CUBEのデフォルトの階層は、①/data/と②/html/になってるけど、普通にこんな構成で、インストール(つまり、ブラウザでユーザがアクセスしてくるときのトップページの階層が1つ下がる)って、ないってばさ。

普通、「http://www.example.com/」でアクセスしてほしいっしょ。トップページは。「http://www.example.com/html/」じゃないでしょ。(^^;

これ、本当意味分からんわ~。運用の問題?まあいいけど。。。

とりあえず、これは、いつでも、ワタクシ的構造的にキモイので、トップページはルートで表示させたいと思います。(ん?それか、普通にデフォルトのまま、インストールしても、インストールのときの設定で変えられるんかなぁ~?いやいや、ルート階層にindex.phpがなかったら、そもそもアクセスできないしネ。やっぱ、だめだよね。うんうん。)

WEBサーバにアップロードする前に、/html/の中の「define.php」を書き換えます。

<?php
/** HTMLディレクトリからのDATAディレクトリの相対パス */
define(“HTML2DATA_DIR”, “/data/”); ←ここ①

/** DATA ディレクトリから HTML ディレクトリの相対パス */
define(“DATA_DIR2HTML”, “../”); ←あと、ここも②

/*
 * Local variables:
 * coding: utf-8
 * tab-width: 4
 * c-basic-offset: 4
 * c-hanging-comment-ender-p: nil
 * End:
 */
?>

そんで、FTPでアップロードするとき、/html/の中身は、全部ドキュメントルート(=一番上の階層)にアップロードして、その中に/data/をアップロードするようにする。

これで、普通にユーザーが、ドメインでアクセスしたら、そこがトップページとして表示されるようになる。

【EC-CUBE】郵便番号DB登録のアップデートは。

新しい住所&郵便番号のDBが郵便局サイトでアップされても、そのままだと、登録時にシステムエラーが出まくる。

  1. KEN_ALL.CSVをダウンロードしてきて、秀丸で開く。
  2. 半角カタカナ→全角カタカナに変換。「~」→「-」に変換。他にもおかしな記号があったら変換。(但し、めっちゃ時間掛かるので、放置して。)
  3. 変換できたら、UTF-8で保存する。
  4. FTPでサーバにつないで、EC-CUBEの「/data/downloads/」のなかに、データを入れ替える。
  5. 後はひたすら管理画面で、登録ボタンを繰り返して押していく。これも結構時間が掛かる。ブラウザの画面が白いままで、読み込みアイコンがぐるぐるやってるときは、大体正常に進んでいる。進んでいるかどうか不審に思うときは、PhpMyAdmin(DBがMySQLのときはね)で、DBの一番下のテーブル(mtb_zip)のレコード数が、増えているかどうか確認して、増えていれば、少しずつだけど登録が進んでいる。最終的には、12万ちょい。

もし、新規のインストールではなくて、一回登録したあとで、アップデートするなら、先に登録されているDBのデータは、PhpMyAdminで値だけ一回削除してしまってから、登録したほうがいい。変なの残ってると困るから。

Home > Tags > カスタマイズ

Search
Feeds
Meta

Return to page top