WordPressとFlashの連携(コンタクトフォーム)
- 2009 年 4月 7 日
WordPressとFlashを連携させてコンタクトフォームを試した記録。
これまで通りWordPressをベースにして極力サーバー側には触らないアプローチで考えます。
かねてより自分的にコンタクトフォームの類いをFlashで作ってもメリットは微妙だよなぁと思ってます。ま、FULL FLASHのサイトでしか使わないだろうから統一感の点は評価できる。クライアント側での入力チェックやトラフィックの軽減といったAjax同様の効果も期待できる。
しかしまぁ、使う側が使いやすいかというと使い慣れたブラウザのフォームが一番な気がするし、実案件ではサーバー環境の制約があったりセキュリティやスパムの対応が必要だとかDBと連動とかFlash側だけではいかんともしがたい条件になることもしばしば。
そういった煩雑な条件になってくるとFlashで作るって以外の交通整理に時間をとられる。交通整理に各方面と連携が必要なわけだけれど、そういった行程やコストもデメリットとなってくるんだよね。
前置きが長くなりすぎました。というわけで、ここではややこしい複雑なことは考えずにコンタクトフォームを考えてみる。方法はWPのプラグインを使ってフォーム作る。出力結果をFlashに読み込み、ごにょごにょするっていう手法。XHTMLに準拠したソースで動いているものならFlashに読み込ませて大抵の処理は出来ると思う。そりゃもう頑張り次第で….。
では早速。
フォームのプラグインは沢山あったのだけれど、日本語環境で評判のよいContact Form 7を使いました。
インストールしたらツールに「Contact Form 7」のメニューが出来るのでここから必要なフォームエレメントと送信メールを設定します。
まずコントロールパネル右上の「タグの作成」で必要なタグを作成。
このタグを「フォーム」に記述していきます。このフォームの記述に応じて、後で設定するページのxhtmlが出力されるので出力結果と見比べて設定を繰り返します。
メールには送信メールを設定。フォームに入力された値をメールに記載するには[key]のように[]でフォーム欄に入力したタグのキーを囲みます。入力したユーザーにコピーを送るなど、別のメールを送りたい場合はメール(2)も使えます。
メッセージでエラーや完了などの通知メッセージを設定できる。
これはこのまま使ってもいいし、使いやすいように数字とかにしちゃってもいいと思う。これもxhtmlの出力と見比べながら設定していく感じで。
設定が済んだらいつものようにページを作る。
ページの本文にコンタクトフォームのコードを記述します。
コンタクトフォームのコードはhtmlタグに置き換わるので、ページのテンプレートは何も記載しない感じ。Safariだと中途半端なhtmlでもレンダリングされたのでヘッダをhtmlにしています。
<?php /* Template Name:cms-form */ ?> <?php header( "Content-Type: text/html; charset=" . get_option( 'blog_charset' ) ); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <?php if (have_posts()) : the_post(); ?> <?php the_content(); ?> <?php endif; ?> |
このページをブラウザで表示すると、http://sample.nipx.jp/wordpress/?page_id=125(ブラウザによっては表示できないかも?)のように表示される
表示の参考
これをFlashで読み込んで表示する。
入力しても送信しないようにしているので操作して確認できます。
xhtmlのフォームエレメントをflashのフォームエレメントに置き換えているだけなのだけれど、まったく整理していない&このxhtml専用の俺俺具合で恥ずかしいくらいごちゃごちゃなソースを晒す…。
ここでは動的にフォームエレメントを生成していますが、設定できるものは通常ステージに配置してコンポーネントインスペクタで設定した方が楽だと思う。
package form{ import caurina.transitions.properties.FilterShortcuts; FilterShortcuts.init(); import fl.controls.Button; import fl.controls.CheckBox; import fl.controls.ComboBox; import fl.controls.Label; import fl.controls.RadioButton; import fl.controls.RadioButtonGroup; import fl.controls.TextArea; import fl.controls.TextInput; import flash.events.Event; import flash.events.MouseEvent; import flash.net.URLRequest; import flash.net.URLRequestMethod; import flash.net.URLVariables; import flash.text.TextFormat; import flash.text.TextFieldAutoSize; import flash.utils.Dictionary; import jp.progression.casts.*; import jp.progression.commands.*; import jp.progression.scenes.SceneObject; import index.loading.Loading; public class FormScene extends SceneObject{ public function FormScene(name:String=null, initObject:Object=null){ super(name, initObject); this.onLoad = this.onLoadHandler; this.container = new CastSprite( { x:10, y:60 } ); this.loading = new Loading( { x:CastDocument.centerX, y:CastDocument.centerY } ); //ローディングを画面中央に生成 } public var request:URLRequest; public var dictionary:Dictionary; public var container:CastSprite; public var loading:Loading; protected function onLoadHandler():void{ this.addCommand( new AddChild( this.progression.container, this.container ), new LoadURL( new URLRequest( "http://sample.nipx.jp/wordpress/?page_id=125" ) ), new Func( function():void{ setup( new XML( this.latestData ), this ); }) ) } public function dummySend(doc:XML):Boolean{ var span:XMLList = doc.descendants("span"); var n:uint = 0; for each(var node:XML in span){ if( node.@["class"] == "wpcf7-not-valid-tip-no-ajax" ){ n++; } } return ( n == 1 ); } //WordPressからのxhtmlを受け取りフォーム画面を生成 //doc = wpからのxhtml, comm = このメソッドはFuncコマンドから実行。そのFuncへの参照 public function setup( doc:XML, comm:Func=null ):void{ //trace( doc ) //フォームの送信先を設定 request = new URLRequest( "http://sample.nipx.jp" + doc.form.@action ); request.method = ( doc.form.@method == "post" ) ? URLRequestMethod.POST : URLRequestMethod.GET; //送信時使う値を格納するDictionary dictionary = new Dictionary( true ); //フォーム生成に利用する変数 var xml:XML; //xml var x:Number = 0; //エレメントのx座標 var y:Number = 0; //エレメントのy座標 var h:Number = 0; //エレメントの高さを一時的に格納 //フロートメッセージ if( doc.div.text().length() ){ //メッセージがあれば処理する //表示メッセージを生成 var format:TextFormat = new TextFormat( "ヒラギノ角ゴ Pro W6", 16, 0x333333 ); var field:CastTextField = new CastTextField( { x:0, y:0 } ); field.defaultTextFormat = format; field.autoSize = TextFieldAutoSize.LEFT; field.text = doc.div.text(); field.x = CastDocument.centerX - field.width /2; field.y = CastDocument.centerY - field.height/2; //送信された時 //if(field.text == "あなたのメッセージは送信されました。ありがとうございました。"){ //正しいif文 if(field.text == "入力内容に不備があります。確認してもう一度送信してください。" && dummySend( doc ) ){ //ダミー対応 field.text = "以上のようにFlashからにフォームを利用できます。ありがとうございました。"; //ダミー対応 field.x = CastDocument.centerX - field.width /2; //ダミー対応 field.y = CastDocument.centerY - field.height/2; //ダミー対応 //メッセージを表示、フォームを非表示、以降のコマンドを削除をコマンドリストに追加 comm.parent.insertCommand( new AddChild( progression.stage, field, { autoAlpha:250 } ), new DoTweener( this.container, { alpha:0, transition:"easeOutSine", time:1 } ), new Wait( 2000 ), new RemoveChild( progression.stage, field, { autoAlpha:250 } ), new Break() ); return void; } //送信されない時 else{ //メッセージを表示し再度フォームを表示をコマンドリストん追加 comm.parent.insertCommand( new AddChild( progression.stage, field, { autoAlpha:250 } ), new Wait( 2000 ), new RemoveChild( progression.stage, field, { autoAlpha:250 } ) ); } } //以前のフォームエレメントを削除 this.container.removeAllChildren(); //hiddenの設定 wpから得るxhtmlの冒頭にhiddenを格納 var hidden:XMLList = doc.descendants("input"); hidden = hidden.( @type == "hidden" ); for each( xml in hidden){ dictionary[ xml.@name.toString() ] = xml.@value; } //フォーム要素の設定 wpから得るxhtmlについてpタグ毎にエレメントを納めている var p:XMLList = doc.descendants("p"); //エレメントの数繰り返す for each( xml in p ){ if( xml.@["class"] == "captcha1" || xml.@["class"] == "captcha2" ){ break; } x = 150; //左の位置を初期化 h = 0; //エレメントの高さを初期化 //ラベルがあれば表示、ラベルはpタグのテキスト要素として記述されている if( xml.text() ){ var label:Label = new Label(); label.textField.autoSize = TextFieldAutoSize.LEFT; label.text = xml.text(); label.y = y; new AddChild( container, label ).execute(); } //エレメントの種類によりタグが異なる為、必要な判別値を用意 var className:String = xml.span.span.@["class"]; var input:XMLList = xml.descendants("input"); var node:XML; //繰り返し時にxmlを格納する変数 //ラジオボタンの場合(class名wpcf7-radioのspanに<input type="radio">が囲まれている) if( className == "wpcf7-radio" ){ var group:RadioButtonGroup; //ラジオボタンのグループ for each( node in input ){ var radio:RadioButton = new RadioButton(); radio.x = x; radio.y = y; group = ( group == null ) ? new RadioButtonGroup( node.@name ) : group; radio.group = group; radio.label = node.@value; radio.value = node.@value; radio.selected = (node.@checked == "checked"); new AddChild( container, radio ).execute(); radio.textField.autoSize = TextFieldAutoSize.LEFT; x+= radio.textField.width + 25; //次のラジオボタンのx位置を設定 h = radio.height; } dictionary[ node.@name.toString() ] = group; } //チェックボックスの場合 else if( className == "wpcf7-checkbox" ){ var arr:Array = []; //このpタグのチェックボックスのインスタンスを格納 for each( node in input ){ var checkbox:CheckBox = new CheckBox(); checkbox.x = x; checkbox.y = y; checkbox.label = node.@value; checkbox.selected = (node.@checked == "checked"); new AddChild( container, checkbox ).execute(); arr.push( checkbox ); checkbox.textField.autoSize = TextFieldAutoSize.LEFT; x+= checkbox.textField.width + 25; //次のチェックボックスのx位置を設定 h = checkbox.height; } dictionary[ node.@name.toString() ] = arr; //Dictionaryに登録 } else{ for each( node in input ){ //テキストの場合 if( node.@type == "text" ){ var text:TextInput = new TextInput(); text.x = x; text.y = y; text.width = 250; text.text = node.@value; new AddChild( container, text ).execute(); dictionary[ node.@name.toString() ] = text; x+= text.width; h = text.height; } //送信ボタンの場合 else if( node.@type == "submit" ){ var submit:Button = new Button(); submit.x = x; submit.y = y; submit.width = 50; submit.label = node.@value; new AddChild( container, submit ).execute(); //dictionary[ node.@name.toString() ] = submit; submit.addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler, false, 0, true ); h = submit.height; } } //セレクトボックスの場合(ここではプルダウンのみの想定) var select:XMLList = xml.descendants("select"); if( select ){ for each( node in select ){ var combobox:ComboBox = new ComboBox(); combobox.x = x; combobox.y = y; combobox.width = 75; var option:XMLList = node.option; var num:uint = 0; for( var i=0; i<option.length(); i++ ){ var op:XML = option[i]; num = ( op.@selected == "selected" ) ? i : num; combobox.addItem( { label:op.text(), data:op.@value } ) } combobox.selectedIndex = num; new AddChild( container, combobox ).execute(); dictionary[ node.@name.toString() ] = combobox; x+= combobox.width; h = combobox.height; } } //テキストエリアの場合 var textareaList:XMLList = xml.descendants("textarea"); if( textareaList ){ for each( node in textareaList ){ var textarea:TextArea = new TextArea(); textarea.x = x; textarea.y = y; textarea.width = 250; textarea.height= 100; textarea.text= node.text(); new AddChild( container, textarea ).execute(); dictionary[ node.@name.toString() ] = textarea; x+= textarea.width; h = textarea.height; } } //エラーメッセージがあればフォームエレメントの右に表示 var span:XMLList = xml.descendants("span"); for each( node in span ){ if( node.(@["class"] == "wpcf7-not-valid-tip-no-ajax" ) ){ var msg:Label = new Label(); msg.textField.autoSize = TextFieldAutoSize.LEFT; msg.text = node.text(); msg.x = x; msg.y = y; new AddChild( container, msg ).execute(); } } } //次の座標を設定 y+=h; y+=10; } } //送信ボタンを押したら送信実行 public function mouseDownHandler(e:MouseEvent):void{ //変数オブジェクトを生成 var vars:URLVariables = new URLVariables(); //dictionaryを参照しキーと値を設定 for( var i:String in dictionary ){ var target = dictionary[i]; if( target is TextInput || target is TextArea ){ //TextInputかTextAreaならtextを格納 vars[ i ] = target.text; } else if( target is Array ){ //Array(チェックボックス)なら配列にチェック済みの値(ラベル)を格納 var arr:Array = []; for( var a=0; a<target.length; a++ ){ var checkbox:CheckBox = target[a] as CheckBox; if( checkbox.selected ){ arr.push( checkbox.label ) } } vars[ i ] = arr; } else if( target is RadioButtonGroup ){ //ラジオボタンなら選択されている値を格納 if( target.selection ){ vars[ i ] = target.selection.value; } } else if( target is ComboBox ){ //セレクトボックスなら選択されている値を格納 vars[ i ] = target.selectedItem.data; } else{ //それ以外(ここではhidden) vars[ i ] = target; } } //変数をリクエストデータに登録 this.request.data = vars; //WPに送信 var comm:SerialList = new SerialList(); comm.addCommand( new AddChild( this.progression.container, this.loading ), new DoTweener( this.container, { _Blur_blurX:20, _Blur_blurY:20, _Blur_quality:3, alpha:0.5, transition:"easeOutSine", time:0.5 } ), new LoadURL( this.request ), new RemoveChild( this.progression.container, this.loading ), new Func( function():void{ setup( new XML( this.latestData ), this ); }), new DoTweener( this.container, { _Blur_blurX:0, _Blur_blurY:0, _Blur_quality:3, alpha:1, transition:"easeOutSine", time:0.5 } ), new Prop( this.container, { filters:null } ) ) comm.execute(); } } } |
結論。フォームはHTMLがいいと思う。