How do I add the GA4 ecommerce dataLayer to WooCommerce? - e-commerce

I am busy with implementing the GA4 ecommerce dataLayer in my WooCommerce site. There are a few plug-ins which can implement the dataLayer for Universal Analytics (e.g. this one, for $99 per year), but I can't find anything for GA4.
This is the dataLayer for the purchase event (source):
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'purchase': {
'transaction_id': 'T12345',
'affiliation': 'Online Store',
'value': '35.43',
'tax': '4.90',
'shipping': '5.99',
'currency': 'EUR',
'coupon': 'SUMMER_SALE',
'items': [{
'item_name': 'Triblend Android T-Shirt',
'item_id': '12345',
'item_price': '15.25',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_variant': 'Gray',
'quantity': 1,
'item_coupon': ''
}, {
'item_name': 'Donut Friday Scented T-Shirt',
'item_id': '67890',
'item_price': '33.75',
'item_brand': 'Google',
'item_category': 'Apparel',
'item_variant': 'Black',
'quantity': 1
}]
}
}
});
Can anyone help me out to put the variables in it?

Found it already i guess:
<script type='text/javascript'>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'purchase': {
'transaction_id': '<?php echo $order->get_order_number(); ?>',
'affiliation': '<?php echo get_option("blogname"); ?>',
'value': '<?php echo number_format($order->get_subtotal(), 2, ".", ""); ?>',
'tax': '<?php echo number_format($order->get_total_tax(), 2 ,".", ""); ?>',
'shipping': '<?php echo number_format($order->calculate_shipping(), 2 , ".", ""); ?>',
'currency': 'EUR',
<?php if($order->get_used_coupons()) : ?>
'coupon': '<?php echo implode("-", $order->get_used_coupons()); ?>',
<?php endif; ?>
'items': [
<?php
foreach ( $order->get_items() as $key => $item ) :
$product = $order->get_product_from_item($item);
$variant_name = ($item['variation_id']) ? wc_get_product($item['variation_id']) : '';
?>
{
'item_name': '<?php echo $item['name']; ?>',
'item_id': '<?php echo $item['product_id']; ?>',
'item_price': '<?php echo number_format($order->get_line_subtotal($item), 2, ".", ""); ?>',
'item_brand': '',
'item_category': '<?php echo strip_tags($product->get_categories(', ', '', '')); ?>',
'item_variant': '<?php echo ($variant_name) ? implode("-" , $variant_name->get_variation_attributes()) : ''; ?>',
'quantity': <?php echo $item['qty']; ?>,
'item_coupon': ''
},
<?php endforeach; ?>
]
}
});
</script>

Just in case anyone else needs a WordPress plugin that can integrate WooCommerce with GA4. There is a solution that can do that using Google Tag Manager:
https://wordpress.org/plugins/gtm-ecommerce-woo/
It covers the purchase and add_to_cart events and takes care of populating those values.

Related

Access selected text (not value) of a select element with Vue

Just trying to access the selected text (not value) of a select element via Vue:
var App = window.App = new Vue({
el: '#app',
data: {
style: '5'
},
computed: {
calctitle: function() {
return this.otype.text;
}
}
});
Just an example style object:
$item = new stdClass();
$item->value = 5;
$item->text = 'Name 1';
$style = array($item);
...
Here i try to create a binding because if i don't cannot submit the form because the option value is "[object Object]", but i need the real int value.
<p>{{calctitle}}</p>
<select v-model="style" name="style">
<option>Choose style</option>
<?php foreach ($style as $item) : ?>
<option value="<?php echo $item->value; ?>" v-bind:otype="{value: <?php echo $item->value; ?>, text: '<?php echo $item->text; ?>'}"><?php echo $item->text; ?></option>
<?php endforeach ?>
</select>
I don't think you'll be able to do it with a computed, since you don't store the selected option anywhere, only its value.
Instead, you can create a data item and use the change event on the select to pull the selected option and set your data value from its textContent.
new Vue({
el: '#app',
data: {
selectedText: '',
style: '5'
},
methods: {
updateFromSelectedText(event) {
const options = event.target.options;
const selectedOption = options[options.selectedIndex];
this.selectedText = selectedOption.textContent;
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<p>{{selectedText}} and {{style}}</p>
<select v-model="style" name="style" #change="updateFromSelectedText">
<option>Choose style</option>
<option value="1">One</option>
<option value="2">Two</option>
<!--option value="<?php echo $item->value; ?>" v-bind:otype="{value: <?php echo $item->value; ?>, text: '<?php echo $item->text; ?>'}"><?php echo $item->text; ?></option-->
</select></div>

yii2 ajax form dose not work new here in yii

This is yii2 form and ajax script which is dose not working any one know how to add ajax to submit form am new here in yii2 please help me wondering here
<script>
$("#frmDemo").submit(function (e)
{
e.preventDefault()
alert('hello');
return false;
var user_fname = $("#usermastermodel-user_fname").val();
var user_lname = $("#usermastermodel-user_lname").val();
var user_mobile = $('#usermastermodel-user_mobile').val();
if (user_fname == "" || user_lname == "" || user_mobile == "")
{
$("#error_message").show().html("All Fields are Required");
} else {
$("#error_message").html("").hide();
$.ajax({
type: "POST",
url: "actionCreate",
data: {user_fname: user_fname, user_lname: user_lname, user_mobile: user_mobile},
success: function (data) {
$('#success_message').fadeIn().html(data);
setTimeout(function () {
$('#success_message').fadeOut("slow");
}, 2000);
}
});
}
})
</script>
This is my form which having name mobile number need to submit this form into db
<?php
$js = Yii::$app->homeUrl . './usermaster/js/jquery-2.1.4.min.js';
$this->registerJsFile($js, ['depends' => yii\web\JqueryAsset::className()]);
?>
<div class="usermaster-model-form">
<?php $form = ActiveForm::begin(['id' => 'frmDemo']); ?>
<?= $form->field($model, 'user_fname')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'user_lname')->textInput(['maxlength' => true]) ?>
<?= $form->field($model, 'user_mobile')->textInput(['maxlength' => true]) ?>
<div class="form-group">
<?= Html::Button($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
To use ajax, syntax is as follows. you can modify your code accordingly. Observe the url pattern carefully, its controller/action. Also you must register js using $this->registerJs();
$.ajax({
type :'POST',
cache : false,
url : '" . yii\helpers\Url::to(["/controller/action"]) . "',
data: {user_fname: user_fname, user_lname: user_lname, user_mobile: user_mobile},
success : function(response) {
// process your response here
}
});
return false;

How create file input at form, which upload file and write link in database

I'm trying to learn Yii2 by writing my own cms.
I want realize attachment photo for shop items. I don't know right way to do this, but i think it's should be so -
On save, files which was selected in multiple file input are uploads to server.
Get the url by each photo
Write links in database cell by template
<div class="itemImgs">
<img class="0" src="{link}"> <!-- first -->
<img class="1" src="{link}"> <!-- second -->
<img class="..." src="{link}"> <!-- ... -->
</div>
Please, help me understand, what i must write in model and\or controller, if its right way. Else, please tell me how should to do it.
Thanks.
UPD
Action in controller:
public function actionCreate() {
$model = new ShopItems();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('create', [
'model' => $model,
'category' => ShopCategories::find()->all()
]);
}
}
Model contain this functions:
public function behaviors() {
return [
TimestampBehavior::className(),
];
}
/** #inheritdoc */
public static function tableName() {return 'shop_items';}
/** #inheritdoc */
public function rules() {
return [
[['category_id', 'title', 'desc', 'price', ], 'required'],
[['category_id', 'price', 'in_stock', 'discount',], 'integer'],
[['desc', 'options',], 'string'],
[['photos',], 'file', 'maxFiles' => 10],
[['title'], 'string', 'max' => 100]
];
}
/** #inheritdoc */
public function attributeLabels() {
return [
'id' => 'ID',
'category_id' => 'Категория',
'title' => 'Название',
'desc' => 'Описание',
'price' => 'Цена',
'discount' => 'Скидка %',
'in_stock' => 'На складе',
'photos' => 'Фото',
'options' => 'Опции',
'created_at' => 'Дата добавления',
'updated_at' => 'Последнее редактирование',
];
}
And the view _form.php:
<?php $form = ActiveForm::begin(); ?>
<div class="col-lg-6">
<?= $form->field($model, 'title')->textInput(['maxlength' => 100]) ?>
<?= $form->field($model, 'desc')->textarea(['class' => 'ckeditor',]); ?>
</div>
<div class="col-lg-6">
<?= $form->field($model, 'category_id')->dropDownList(
ArrayHelper::map($category, 'category_id', 'category_name')
) ?>
<?= $form->field($model, 'price')->textInput() ?>
<?= $form->field($model, 'discount')->textInput() ?>
<?= $form->field($model, 'in_stock')->textInput() ?>
<?= $form->field($model, 'photos[]')->fileInput(['multiple' => true]) ?>
<?= $form->field($model, 'options')->textInput() ?>
</div>
<div class="clearfix"></div>
<div class="col-xs-12">
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Добавить' : 'Принять изменения', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
</div>
<?php ActiveForm::end(); ?>
See documentation - http://www.yiiframework.com/doc-2.0/guide-input-file-upload.html#uploading-multiple-files
In controller:
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
}
}
Input model Photo:
if ($model->file && $model->validate()) {
foreach ($model->file as $file) {
$path = 'uploads/' . $file->baseName . '.' . $file->extension;
$file->saveAs($path);
$photo = new Photo();
$photo->path = $path;
$photo->save();
}
}
Photo table like that:
CREATE TABLE `photo` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`path` VARCHAR(255) NOT NULL ,
`status` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
ENGINE=InnoDB;
Get photos use:
$photos = Photo::find()->all();
In view:
<div class="itemImgs">
<?php foreach ($photos as $k=>$photo) ?>
<img class="<?= $k ?>" src="<?= $photo->path ?>"/><br/>
<?php } ?>
</div>
EDIT
Set in controller
if ($model->load(Yii::$app->request->post()) && $model->validate()) {
$files = UploadedFile::getInstances($model, 'file');
$photosArr = [];
foreach ($files as $file) {
$path = 'uploads/' . $file->baseName . '.' . $file->extension;
$file->saveAs($path);
$photosArr[] = $path;
}
$model->photos = Json::encode($photosArr);// better put json in afterSave
$model->save(false);// because validate() run before
return $this->redirect(['view', 'id' => $model->id]);
}
In field photos you get JSON with path for uploaded photos. In view:
$arr = Json::decode($model->photos); // better put in afterFind()
foreach ($arr as $path) {
echo '<img src="'.$path.'">';
}

yii modal dialog login

I've been looking all over the internet and I can't seem to find the solution to just a simple login via header. I tried all sorts of way. The problem I have right now just reloads every time i hit login. It's only when I go to ?r=site/login it'll let me login. Is there some kind of controller for headers!??! Not sure what is wrong anymore.
Right now i have this in my header:
<?php $this->beginWidget(
'bootstrap.widgets.TbModal',
array('id' => 'login')
); ?>
<?php
$model=new LoginForm;
$this->renderPartial('//site/login', array('model'=>$model));
?>
<?php $this->endWidget(); ?>
//stuff here
<?php $this->widget(
'bootstrap.widgets.TbButton',
array(
'label' => 'Signin',
'type' => 'warning',
'htmlOptions' => array(
'data-toggle' => 'modal',
'data-target' => '#login',
),
)
);
?>
And then in site/login:
<div class="spacing">
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'login-form',
'enableClientValidation'=>true,
'clientOptions'=>array(
'validateOnSubmit'=>true,
),
)); ?>
<div class="form" id="login-form">
<div class="login-container">
<div class="login-header">
<h1 title="login">Sign In</h1>
</div>
<div class="login-form">
<div class="input-position">
<?php echo $form->labelEx($model,'Email',array('class'=>'span3','style'=>'text-align:left')); ?>
<?php echo $form->textField($model,'email', array('class'=>'span3')); ?>
<?php echo $form->error($model,'email'); ?>
</div>
<div class="input-position">
<?php echo $form->labelEx($model,'password',array('class'=>'span3','style'=>'text-align:left')); ?>
<?php echo $form->passwordField($model,'password',array('class'=>'span3',)); ?>
<?php echo $form->error($model,'password'); ?>
</div>
<div class="input-position ">
<div class="rememberMe">
<?php echo $form->checkBox($model,'rememberMe'); ?>
<?php echo $form->label($model,'rememberMe'); ?>
<?php echo $form->error($model,'rememberMe'); ?>
</div>
</div>
<div class="row buttons">
<?php echo CHtml::submitButton('Login'); ?>
</div>
<?php $this->endWidget(); ?>
</div>
</div>
</div>
</div>
</div>
controller
public function actionLogin()
{
$model=new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if($model->validate() && $model->login())
$this->redirect(Yii::app()->user->returnUrl);
}
// display the login form
$this->render('login',array('model'=>$model));
}
As per my understanding, please keep your login script inside some loop like this to escape it from reloading every time.
if(Yii::app()->user->isGuest and (Yii::app()->controller->id=='site' and Yii::app()->controller->action->id = 'login')){
$this->beginWidget('bootstrap.widgets.TbModal', array('id' => 'login'));
---
$this->endWidget();
}else{
// keep some log out or other script here.
}
Here is the login what i have implemented on Modal login style:
Component/Header:
<?php
Yii::import('zii.widgets.CPortlet');
class Header extends CPortlet
{
protected function renderContent()
{
$this->render('Header');
}
}
Components/view/Header.php
<?php if(Yii::app()->user->isGuest){?>
<?php echo TbHtml::link('<i class="sign-in"></i>Sign in', '#', array(
'data-toggle' => 'modal',
'data-target' => '#loginModal',
));?>
<?php } else{ echo 'Hi!'.$user; } ?>
In View/Layout/Main.php
<?php
$model = new LoginForm;
$this->widget('bootstrap.widgets.TbModal', array(
'id' => 'loginModal',
'header' => '<h3 id="loginModal">Sign In</h3>',
'content'=> $this->renderPartial('userlogin',array('model'=>$model),true),
'remote' => $this->createUrl('site/userlogin'),
'onShow'=>'function(){$("#login-form")[0].reset(); }',
'show'=>false,)); ?>
View/Site/Userlogin.php
<?php $form = $this->beginWidget('bootstrap.widgets.TbActiveForm', array(
'id'=>'login-form',
//'helpType'=>'help-none',
'action'=>Yii::app()->createUrl('userlogin'),
//'enableAjaxValidation' => false,
'enableClientValidation'=>true,
'clientOptions' => array(
'validateOnSubmit' => true,
'validateOnChange'=>false,
'afterValidate' => 'js:function(form, data, hasError) {
if (!hasError){
str = $("#login-form").serialize() + "&ajax=login-form";
$.ajax({
type: "POST",
url: "' . Yii::app()->createUrl('site/userlogin') . '",
data: str,
dataType: "json",
beforeSend : function() {
$("#login").attr("disabled",true);
},
success: function(data, status) {
if(data.authenticated)
{
window.location = data.redirectUrl;
}
else
{
$.each(data, function(key, value) {
var div = "#"+key+"_em_";
$(div).text(value);
$(div).show();
});
$("#login").attr("disabled",false);
}
},
});
return false;
}
}',
),
));?>
<?php echo $form->textFieldControlGroup($model,'username',array('span'=>5,'maxlength'=>255,'required'=>true)); ?>
<?php echo $form->passwordFieldControlGroup($model,'password',array('span'=>5,'maxlength'=>255,'required'=>true)); ?>
<?php echo TbHtml::submitbutton('Sign In',array('class'=>'btn btn-primary')); ?>
<?php $this->endWidget(); ?>
This will Authenticate via Ajax
SiteController:
$model=new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
$errors = CActiveForm::validate($model);
if ($errors != '[]')
{
echo $errors;
Yii::app()->end();
}
}
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if ($model->validate() && $model->login()) {
if (isset($_POST['ajax']) && $_POST['ajax'] === 'login-form') {
$user_id = Yii::app()->user->id;
$arr = array();
$record = Users::model()->findByPk($user_id);
if ($record) {
echo CJSON::encode(array( 'authenticated' => true,
'redirectUrl' => CController::createUrl('users/trainerprofile'),
"id" => $record->id,));
Yii::app()->end();
}
}

yii modal box form validation

I am using yii framework for my website. I have a signup form in modal box. If i submit the form without fill the validation errors should show within the modal box without refresh. But now it redirects to some other page. How can i show the validation errors within the modal box in the same page?
This is the code that i have used for sign up view
<?php
$model=new SignupForm;
$form=$this->beginWidget('CActiveForm', array(
'id'=>'signup-form',
'enableAjaxValidation'=>true,
'action'=>'site/signup'
));
?>
<?php echo $form->errorSummary($model); ?>
<?php echo $form->textField($model,'name',array('value'=>'Enter Your Name', 'onclick'=>'javascript:this.value=""', 'onblur'=> 'this.value = ( this.value == "" ) ? "Enter Your Name" : this.value;')); ?><br />
<?php echo $form->textField($model,'email',array('value'=>'Enter Your Email ID', 'onclick'=>'javascript:this.value=""', 'onblur'=> 'this.value = ( this.value == "" ) ? "Enter Your Email ID" : this.value;')); ?><br />
<?php echo $form->textField($model,'phone',array('value'=>'Telephone', 'onclick'=>'javascript:this.value=""', 'onblur'=> 'this.value = ( this.value == "" ) ? "Telephone" : this.value;')); ?><br />
<!--<input type="text" value="username" onClick="this.value=''"/><br/>
<input type="password" value="Password" onClick="this.value=''"/> -->
<div class="d-login"><?php echo CHtml::submitButton('Submit'); ?>
<?php /*?><input type="image" alt="Login" title="Login" src="<?php echo Yii::app()->request->baseUrl; ?>/images/signup.png"/><?php */?>
</div>
<?php $this->endWidget(); ?>
The code in controller:
public function actionSignup()
{
$model=new SignupForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='signup-form')
{
$model->attributes=$_POST['SignupForm'];
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect input data
if(isset($_POST['SignupForm']))
{
$model->attributes=$_POST['SignupForm'];
$name=$model->name;
$email=$model->email;
$phone=$model->phone;
$newsletter = new Newsletter();
if($model->validate())
{
//insert data
$newsletter->varName = $name;
$newsletter->varEmail = $email;
$newsletter->varPhone = $phone;
if($newsletter->save()) {
$url = Yii::app()->getBaseUrl();
Yii::app()->getRequest()->redirect($url);
}
}
}
$this->render('signup',array('model'=>$model));
}
You have to use ajax and renderPartial if you want to validate a model inside a dialog modal box. below is an untested code.(From this link )
in your views/signup.php
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'signup-form',
'enableAjaxValidation'=>false,
));
?>
<?php echo $form->errorSummary($model); ?>
<?php echo $form->textField($model,'name',array('value'=>'Enter Your Name', 'onclick'=>'javascript:this.value=""', 'onblur'=> 'this.value = ( this.value == "" ) ? "Enter Your Name" : this.value;')); ?><br />
<?php echo $form->textField($model,'email',array('value'=>'Enter Your Email ID', 'onclick'=>'javascript:this.value=""', 'onblur'=> 'this.value = ( this.value == "" ) ? "Enter Your Email ID" : this.value;')); ?><br />
<?php echo $form->textField($model,'phone',array('value'=>'Telephone', 'onclick'=>'javascript:this.value=""', 'onblur'=> 'this.value = ( this.value == "" ) ? "Telephone" : this.value;')); ?><br />
<div class="d-login">
<?php echo CHtml::submitButton('Submit'); ?>
</div>
<?php $this->endWidget(); ?>
</div>
In your controller
public function actionSignup()
{
$model=new SignupForm;
if(isset($_POST['SignupForm']))
{
$model->attributes=$_POST['SignupForm'];
$name=$model->name;
$email=$model->email;
$phone=$model->phone;
$newsletter = new Newsletter();
if($model->save())
{
//insert data
$newsletter->varName = $name;
$newsletter->varEmail = $email;
$newsletter->varPhone = $phone;
if($newsletter->save())
{
if (Yii::app()->request->isAjaxRequest)
{
echo CJSON::encode(array(
'status'=>'success',
));
exit;
}
else
{
$url = Yii::app()->getBaseUrl();
Yii::app()->getRequest()->redirect($url);
}
}
}
if (Yii::app()->request->isAjaxRequest)
{
echo CJSON::encode(array(
'status'=>'failure',
'div'=>$this->renderPartial('signup', array('model'=>$model), true)));
exit;
}
else
$this->render('signup',array('model'=>$model,));
}
And finally in your view file where you want to display the signup modal box
<?php echo CHtml::link('Signup', "", // the link for open the dialog modal
array(
'style'=>'cursor: pointer; text-decoration: underline;',
'onclick'=>"{doSignup(); $('#dialogSignup').dialog('open');}"));?>
<?php
$this->beginWidget('zii.widgets.jui.CJuiDialog', array( // the dialog
'id'=>'dialogSignup',
'options'=>array(
'title'=>'Signup',
'autoOpen'=>false,
'modal'=>true,
'width'=>550,
'height'=>470,
),
));?>
<div class="divForForm"></div>
<?php $this->endWidget();?>
<script type="text/javascript">
function doSignup()
{
<?php echo CHtml::ajax(array(
'url'=>array('site/signup'),
'data'=> "js:$(this).serialize()",
'type'=>'post',
'dataType'=>'json',
'success'=>"function(data)
{
if (data.status == 'failure')
{
$('#dialogSignup div.divForForm').html(data.div);
$('#dialogSignup div.divForForm form').submit(doSignup);
}
else
{
window.location.href =".Yii::app()->getBaseUrl().";
}
} ",
))?>;
return false;
}
</script>
You should define the validation rules in signup model.. Or paste your sign up model here..