修改用戶頁面的密碼欄位

要求看似簡單,將用戶頁面的密碼欄位改成 “New Password” (或加 placeholder 等)

由:

改成:

試過使用最簡單的 hook_form_alter user_profile_form 但不成功,其中一個元素 <?php $form['account']['pass']['#type'] = 'password_confirm';?>
沒有 #title 可以修改

而原來 ‘password_confirm’ 是由 form_process_password_confirm() 輸出的,其中並沒有提供 hook

所以便要另找途徑,使用 form API #pre_render

<?php
function hook_form_user_profile_form_alter(&$form, &$form_state) {
 
$form['#pre_render'][] = 'hook_form_user_profile_form_pre_render';
}
function
hook_form_user_profile_form_pre_render($elements) {
 
$elements['account']['pass']['pass1']['#title'] = t('New password');
 
$elements['account']['pass']['pass2']['#title'] = t('Confirm new password');
  return
$elements;
}
?>

完成

訪客購物車 programmatically


需求:每個訪客都會預設幫他們將一件貨物加到購物車
他們便可以直接完成交易

Commerce kickstart已經是一個現成的示範
訪客就算不注冊仍然可以使用購物車
而且一定情況之下關閉瀏覽器之後再回到網站仍然可以找回上次的紀錄繼續購物

但在 init 的時候使用

<?php
commerce_order_new
(0);
?>
是不會將 order 連接到現有的瀏覽器進程的

你需要的是:

<?php
commerce_cart_order_session_save
($order->order_id);
?>
AttachmentSize
download.png11.64 KB

Drupal commerce - 從代碼建立訂單


Drupal commerce 己經成為 Drupal 電子商務應用的主流了,ubercart 落伍了

Ubercart 是一個源自 Drupal5.x 世代的方案
而為了使用 Drupal7 方便的 entities,和令電子商務方案使用一個「弱品牌化」的名字,Drupal commerce 誕生了

但因為 Drupal commerce 龐大的代碼量,為了方便分散工作,代碼都打散到不同的模組,各自有他們的維護者
再加上為數不少的 dependencies 令上手的難度過大
所以 Drupal commerce kickstart 便將一個完整的電子商務網站包裝起來
只需要下載安裝,匯入範例便可以立即使用了

這次的開發和前一次類似,從代碼建立將貨物放到訂單:

<?php
$cp
= commerce_product_new($type);
$cp->is_new = TRUE;
$cp->revision_id = NULL;
$cp->uid = $user->uid;
$cp->status = 1;
$cp->language = LANGUAGE_NONE;   
$cp->created = $cp->changed = time();
$cp->sku = 'shirt_od' . $extras['title'] . drupal_hash_base64(microtime());
$cp->title = $cp->sku;
?>

使用

<?php
field_attach_submit
()
?>
儲存貨品,便可以觸發相對應的 hooks 了:
<?php
$price
= array(LANGUAGE_NONE => array(0 => array(
   
'amount' => $price * 100,
   
'currency_code' => commerce_default_currency(),
)));
$form_state['values']['commerce_price'] = $price;

// custom fields
$form_state['values']['field_quantity']     = array(LANGUAGE_NONE => array(0 => array('value' => $quantity)));
$unit_price = array(LANGUAGE_NONE => array(0 => array(
   
'amount' => $unit_price * 100,
   
'currency_code' => commerce_default_currency(),
)));
$form_state['values']['field_unit_price']     = $unit_price;
field_attach_submit('commerce_product', $cp, $form, $form_state);

commerce_product_save($cp);
?>

購物車:

<?php
$order
= commerce_order_new($uid, 'cart');
commerce_order_save($order);

$line_item = commerce_product_line_item_new($cp, 1, $order->order_id);
// Save the line item to get its ID.
commerce_line_item_save($line_item);

// Add the line item to the order using fago's rockin' wrapper.
$order_wrapper = entity_metadata_wrapper('commerce_order', $order);
$order_wrapper->commerce_line_items[] = $line_item;

// Save the order again to update its line item reference field.
commerce_order_save($order);
?>

Drupal feeds module: FeedsProcessor with ubercart Order

使用者情境:批量使用 CSV 匯入 ubercart 訂單

Feeds 模組已經有一個 CSV 格式讀取 parser,又有批量 batch 支持,能處理大檔案 CSV ,Feeds 的代碼也有很多使用的經驗,而且最重要的是,模組自己已經有四種內容可以匯入:(nodes, users, terms, feednode?),有更高的機會支持其他內容 (ubercart orders)

先從 “The developer's guide to Feeds” 開始研究:(https://www.drupal.org/node/622700)
有三種 plugin: fetcher,parser 和 processor

  • Fetcher 是「獲得匯入源的方法」feeds module 已經有一個檔案上載的 fetcher
  • Parser 是「如何分析,讀取匯入源」feeds module 已經有一個 CSV parser
  • Processer 的工作是將處理過的資料儲存成為 Drupal 的內容

建立一個新模組 ubercart_order_feeds.module:

<?php
/**
* Implementation of hook_feeds_plugins().
* http://drupalcontrib.org/api/drupal/contributions%21feeds%21feeds.api.php/function/hook_feeds_plugins/6
*/
function ubercart_order_feeds_feeds_plugins() {
 
$path = drupal_get_path('module', 'ubercart_order_feeds');
 
$info = array();
 
$info['FeedsOrderProcessor'] = array(
   
'name' => 'Order processor',
   
'description' => 'Create orders.',
   
'help' => 'Create orders from parsed content.',
   
'handler' => array(
     
'parent' => 'FeedsProcessor',
     
'class' => 'FeedsOrderProcessor',
     
'file' => 'FeedsOrderProcessor.inc',
     
'path' => $path,
    ),
  );
  return
$info;
}
?>

建立一個新檔案 FeedsOrderProcessor.inc:
<?php
class FeedsOrderProcessor extends FeedsProcessor {
}
?>

首先在 getMappingTargets() 定義 CSV 中會用到的欄位:

<?php
 
/**
   * Return available mapping targets.
   */
 
public function getMappingTargets() {
   
$targets = array(
     
'sku' => array(
       
'name' => t('Product SKU'),
       
'description' => t('SKU of the product.'),
      ),
     
'quantity' => array(
       
'name' => t('Quantity'),
       
'description' => t(''),
      ),
     
'cost' => array(
       
'name' => t('Cost'),
       
'description' => t(''),
      ),
     
'delivery_first_name' => array(
       
'name' => t('Delivery: First name'),
       
'description' => t(''),
      ),
     
'delivery_last_name' => array(
       
'name' => t('Delivery: Last name'),
       
'description' => t(''),
      ),
   
//....
?>

在 CSV 內的資料處理過之後,資料的值會根據 Array 的 key 放到 object 之內.

我輸出了一個原生的 order object,找出原本就有的預設欄名,定義 mappings 的時候重用它們,以省卻一點點麻煩 (i.e. delivery_first_name, delivery_last_name above and more)

process() 是主要的程式進入點,複製一點 NodeProcessor 的代碼:

<?php
 
public function process(FeedsImportBatch $batch, FeedsSource $source) {
   
// Count number of created and updated nodes.
   
$created  = $updated = $failed = 0;

    while (
$item = $batch->shiftItem()) {
     
// Map item to a term.
     
$order = $this->map($batch);
     
//.......
?>

來到這一點出現一個新的函數 map() 來返回一個全新的 ubercart order object:

<?php
 
/**
   * Execute mapping on an item.
   */
 
protected function map(FeedsImportBatch $batch, $target_order = NULL) {
   
// Prepare user account object.
   
if (empty($target_order)) {
     
$order = uc_order_new($user->uid, 'completed');
    }

   
// Have parent class do the iterating.
   
return parent::map($batch, $order);
  }
?>

parent::map() 函數會將 CSV 內的資料處理過之後,根據 mapping array 的 key 放到 object

程式化的建立 order

process() 的下一步是將 product 加到 order,並儲存之

使用 vid 載入一個 product: <?php uc_product_load() ?>
http://drupalcontrib.org/api/drupal/contributions!ubercart!uc_product!uc...

加 product 到 order:
<?php $order->products[] = $product; ?>

再填入一些 order 的基本 mail 和 payment method 之後,儲存,完成 sale:

<?php
uc_order_save
($order);
uc_cart_complete_sale($order, TRUE);
?>

你亦可以加入 payment method
<?php uc_payment_enter($order->order_id, 'bank_transfer', 0, 0, NULL, t('Checkout completed for a free order.')); ?>

Github 源碼 repo: https://github.com/joetsuihk/ubercart_order_feeds

One more thing

Processor 可以有自己的設定頁面
在我的情境,因為客戶會將同一個模組放到不同的網站,而他們有不同的 webform node ID
所以我便將 ID 放到設定頁面令客戶可以更方便的修改設定了

<?php
 
/**
   * Override parent::configDefaults().
   */
 
public function configDefaults() {
    return array(
     
'card_form_id' => '',
     
'mappings' => array(),
    );
  }

  public function
configForm(&$form_state) {
   
$form = array();
   
$form['card_form_id'] = array(
     
'#type' => 'textfield',
     
'#title' => t('Card webform node ID'),
     
'#default_value' => $this->config['card_form_id'],
    );
    return
$form;
  }
?>

Pages

Google