Edit woocommerce Login register page - authentication

I am using woocommerce for an eCommerce website. I want to add one more field in Login Regiser page. On this page there are three fields in registration (Email, Password and Re-enter password) and I want to add one more field for phone number.
Can anybody help me ? Thanks in Advance
http://wordpress.org/plugins/woocommerce/

If anyone else is curious on how to add additional fields to the login/register/any other account forms. You can achieve this quite easily since WooCommerce has added those to their templates folder. All you have to do is copy-paste the form you need to modify from plugins>woocommerce>templates>myaccount and drop it into your own theme. After which, you can add your extra fields and add any other functionality to make them work using http://docs.woothemes.com/document/hooks/
Hope this is of help to anyone who's been stuck on this.

I Use the "Register Plus Redux" plugin and use the "billing_phone" Database key to map to the correct field in the the User database. You can also have the user add other Information such as "'billing_address_1" and any others.
Best Regards
Marc

Old post, but this answer deals with the question as asked and provides a direct answer form the WordPress Codex
I have modified the code from the pages linked to act inline with the zipcode example that appears on the validation page. Each page within the codes used different examples, I just made them all the same.
Add the custom field
Plugin API/Action Reference/register form
The 'register_form' action hook is used to customize the built-in WordPress registration form.
Use in conjunction with 'registration_errors' (for validation) and 'register_post' (save extra data) when customizing registration.
WordPress MS Note: For Wordpress MS (Multi-Site), use the 'signup_header' action to redirect users away from the signup. (emphasis mine, took me a while to realise this)
Example
This example demonstrates how to add a new field to the registration form. Keep in mind that this won't be saved automatically. You will still need to set up validation rules and manually handle saving of the additional form fields.
add_action( 'register_form', 'myplugin_add_registration_fields' );
function myplugin_add_registration_fields() {
//Get and set any values already sent
$zipcode = ( isset( $_POST['zipcode'] ) ) ? $_POST['zipcode'] : '';
?>
<p>
<label for="user_extra"><?php _e( 'Extra Field', 'myplugin_textdomain' ) ?><br />
<input type="text" name="user_extra" id="user_extra" class="input" value="<?php echo esc_attr( stripslashes( $zipcode ) ); ?>" size="25" /></label>
</p>
<?php
}
link: https://codex.wordpress.org/Plugin_API/Action_Reference/login_form
Validation
You need to validate the user input (obviously) and should run that throughregistration_errors filter hook. Be mindful, the $errors variable may already be populated by other errors from the registration process. As in the examples, you would add your error to errors already contained therein.
Returning an Error
function myplugin_check_fields( $errors, $sanitized_user_login, $user_email ) {
$errors->add( 'demo_error', __( '<strong>ERROR</strong>: This is a demo error.', 'my_textdomain' ) );
return $errors;
}
add_filter( 'registration_errors', 'myplugin_check_fields', 10, 3 );
Validating a Custom Field
(this next section deals specifically with validation of the custom field)
Assuming you wanted to validate a postal code field that you have already created using the register_form hook, you might validate the field like so:
function myplugin_check_fields( $errors, $sanitized_user_login, $user_email ) {
if ( ! preg_match('/[0-9]{5}/', $_POST['zipcode'] ) ) {
$errors->add( 'zipcode_error', __( '<strong>ERROR</strong>: Invalid Zip.', 'my_textdomain' ) );
}
return $errors;
}
add_filter( 'registration_errors', 'myplugin_check_fields', 10, 3 );
link: https://codex.wordpress.org/Plugin_API/Filter_Reference/registration_errors
finally, don't forget to save the custom field's data!
add_action( 'user_register', 'myplugin_registration_save', 10, 1 );
function myplugin_registration_save( $user_id ) {
if ( isset( $_POST['zipcode'] ) )
update_user_meta($user_id, 'zipcode', $_POST['zipcode']);
}
link: https://codex.wordpress.org/Plugin_API/Action_Reference/user_register
A complete example
At the end of all this I ended up coming across a tutorial to do exactly this. In this example they are adding a First Name field:
//1. Add a new form element...
add_action( 'register_form', 'myplugin_register_form' );
function myplugin_register_form() {
$first_name = ( ! empty( $_POST['first_name'] ) ) ? sanitize_text_field( $_POST['first_name'] ) : '';
?>
<p>
<label for="first_name"><?php _e( 'First Name', 'mydomain' ) ?><br />
<input type="text" name="first_name" id="first_name" class="input" value="<?php echo esc_attr( $first_name ); ?>" size="25" /></label>
</p>
<?php
}
//2. Add validation. In this case, we make sure first_name is required.
add_filter( 'registration_errors', 'myplugin_registration_errors', 10, 3 );
function myplugin_registration_errors( $errors, $sanitized_user_login, $user_email ) {
if ( empty( $_POST['first_name'] ) || ! empty( $_POST['first_name'] ) && trim( $_POST['first_name'] ) == '' ) {
$errors->add( 'first_name_error', sprintf('<strong>%s</strong>: %s',__( 'ERROR', 'mydomain' ),__( 'You must include a first name.', 'mydomain' ) ) );
}
return $errors;
}
//3. Finally, save our extra registration user meta.
add_action( 'user_register', 'myplugin_user_register' );
function myplugin_user_register( $user_id ) {
if ( ! empty( $_POST['first_name'] ) ) {
update_user_meta( $user_id, 'first_name', sanitize_text_field( $_POST['first_name'] ) );
}
}
https://codex.wordpress.org/Customizing_the_Registration_Form

Related

How do i add whatsapp api link to email orders using the customer phone number?

I would like to add whatsapp link to admin complete orders email, that takes the customer phone number, and adds it to the whatsapp api link.
The idea is that, when i receive notification about order, i can contact my customer using whatsapp and let him know i got his order.
so it should look like this:
api.whatsapp.com/send?phone= {{customer phone number}} &text=...
Add the follows code snippet in your active theme's functions.php and changes the text messages as per you.
function add_wp_link_woocommerce_completed_order_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_completed_order' || $email->id == 'new_order' ) {
$link = 'https://wa.me/'.$order->get_billing_phone( 'edit' ).'/?text='.urlencode( 'your text messages' );
echo '<div style="margin-bottom: 40px;">
<h2>'.__( 'Customer WhatsApp link', 'text-domain' ) .'</h2>
<p>'.__( 'Contact', 'text-domain' ).'</p>
</div>';
}
}
add_action( 'woocommerce_email_customer_details', 'add_wp_link_woocommerce_completed_order_email', 99, 4 );

Method not receiving attributes from shortcode call, general OOP problems

The method OpenMods that you see below, is supposed to take an array generated by an fgetcsv function, and put it into an HTML table. __construct is supposed to, as is typically the case, define the attributes for the class, and shortcode is supposed to take two attributes from the shortcode, and if mods comes back, it is supposed to call another function in the class.
OpenMods did function when it was outside of a class, without the class attribute calls, so I'm fairly certain that isn't the source of my problem. My problem most likely lies within __construct and shortcode; However please don't overlook OpenMods as it may contain errors that are contributing to the problem, I'm just giving my estimation which isn't worth much since I'm having to ask to for help.
This is an example of the shortcode I'm trying to make work:
[priceguide file=’test.csv’ type=’mods’]
class CsvImporter
{
private $parse_header;
private $header;
private $delimiter;
private $length;
//--------------------------------------------------------------------
function __construct($parse_header=false, $delimiter="\t", $length=8000)
{
add_shortcode( 'priceguide', array( $this, 'shortcode' ) );
$this->parse_header = $parse_header;
$this->delimiter = $delimiter;
$this->length = $length;
}
//--------------------------------------------------------------------
public function shortcode($atts) {
$attributes = extract( shortcode_atts( array(
'file' => '',
'type' => '',
), $atts ));
if ($attributes['mods'])
{
$this->OpenMods($attributes['file']);
}
}
//--------------------------------------------------------------------
function OpenMods($file) {
ob_start();
$fp = fopen(plugin_dir_path( __FILE__ ) . $file , "r" );
if ($this->parse_header)
{
$header = fgetcsv($fp, $this->length, $this->delimiter);
}
// table header and search html
echo('<input type="text" class="search" id="search" placeholder="Search">');
echo('<br>');
echo('<table id="table"> <tr class="hidden">
<th><b>
Name</b>
</th>
<th><b>
Cheese</b>
</th>
<th><b>
Price</b>
</th>
<th><b>Vote</b>
</th>
</tr>
<tbody>');
// integer for drop down/price submit
$a = 1;
// set values for table data
while ($header !== FALSE) {
$name = $header[0];
$quanid = $header[2];
$table = $header[3];
unset($header[2]);
unset($header[3]);
$cssId = 'row-'.$a;
$a++;
//generate HTML
echo('<tr>');
foreach ($header as $index=>$val) {
echo('<td>');
echo htmlentities($val, ENT_QUOTES);
echo('</td>');
}
// query to get item prices
$sql = "SELECT ItemID, Price
FROM {$table}
WHERE ItemID = %d
GROUP BY Price
ORDER BY COUNT(*) DESC LIMIT 1";
global $wpdb;
$results = $wpdb->get_var( $wpdb->prepare( $sql, $quanid));
// put the results in the table
echo('<td>');
print_r($results);
echo('</td>');
// HTML for hidden row/price submission
echo('<td>
<button class="toggler" data-prod-cat="' . $cssId . '">Vote</button>
</td>');
echo('</tr>');
echo('<tr class="cat' . $cssId . ' hidden" style="display:none">');
echo('<td colspan="4" style="white-space: nowrap">Enter ' . $name . ' Price:
<form action="" name="form' . $quanid . '" method="post"><input type="text" id="' . $quanid . '" maxlength="4" name="' . $quanid . '" value="price_input" class="input" />
<button id="submit" name="submit" class="submit" type="submit" value="Submit">Submit</button></form>
<?php
?>
</td>
</tr>');
wp_nonce_field('price_input');
}
echo("</table>");
fclose($fp);
return ob_get_clean();
}
}
Based on OP comment, the problem is, the object can not created and in this case, __constructor() will not run, and add_shortcode( 'priceguide', array( $this, 'shortcode' ) ); will never triggered.
There are two solutions. One, if you are make the shortcode method to static, and add this in your functions.php file:
add_shortcode( 'priceguide', 'CsvImporter::shortcode' ) );
The second option, if you do not want to make it static if you instantiate an object from your class, before anythings happens. In your functions.php
add_action('init', 'my_init');
global $CsvImporter;
function my_init() {
global $CsvImporter;
$CsvImporter = new CsvImporter();
}
In this case, when no output send to the buffer, you create a new CsvImporter object, so the __construct() will run, so shortcode will registered.

DropDownList won't POST value by using ajax

I created DropDownList and I'm trying to fill div with content and I know how to do it. But problem is that my dropdown list won't POST value.
This is code from view\index.php
<?php
echo CHtml::dropDownList('parovi', '', $model->dropDownListParovi(), array
(
'class'=>'dropDownListLegloIzaberiPar',
'empty'=>array('-'=>Yii::t('default', 'PAR_UZGOJNI_DNEVNIK_LEZENJA_IZABERI_PAR')),
'ajax'=>array
(
'type'=>'POST',
'url'=>Yii::app()->createUrl('/paruzgojni/ajaxIzlistajLegla'),
'update'=>'#legla',
),
)
);
?>
<div id="legla"></div>
And this is from controller
public function actionAjaxIzlistajLegla()
{
echo $_POST['parovi'];
}
this AjaxIzlistaijLegla action is inside accessRules(). And it's working cause When I replace echo $_POST['parovi']; with echo "Hello"; it works, it updates my div. But I don't know why it won't POST that value from drop down list.
jquery is included in head.
Answer is I should wrap my dropDownList with CActiveForm like this
$this->beginWidget('CActiveForm', array(
'id'=>'par-uzgojni-ispis-legla-form',
));
echo CHtml::dropDownList('parovi', '', $model->dropDownListParovi(), array
(
'class'=>'dropDownListLegloIzaberiPar',
'empty'=>array('-'=>Yii::t('default', 'PAR_UZGOJNI_DNEVNIK_LEZENJA_IZABERI_PAR')),
'ajax'=>array
(
'type'=>'POST',
'url'=>Yii::app()->createUrl('/paruzgojni/ajaxIzlistajLegla'),
'update'=>'#legla',
),
)
);
$this->endWidget();
Because I didn't wrap it, it couldn't POST any data to my controller

Can't update product in magento module

have an issue updating magento product from frontend using a module that its function is for customers to create their own products and have the admin approve before enabled(this part is working).
the problem is when a customer tries to updated their admin approved product (as before approval, product states that newly created product is pending, but they can still update the data/attributes created during the product create function, the same attributes that are not updating using the controller)
first of all i have a controller with the action to update the approved/pending customer product
public function editPostAction() {
$id = $this->getRequest()->getParam('productid');
if ( $id !== false ) {
list($data, $errors) = $this->validatePost();
if ( !empty($errors) ) {
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
$this->_redirect('customer/products/edit/', array(
'id' => $id
));
} else {
$customerId = $this->_getSession()->getCustomer()->getid();
$product = Mage::getResourceModel('customerpartner/customerpartner_product_collection')
->addAttributeToSelect('*')
->addAttributeToFilter('customer_id', $customerId)
->addAttributeToFilter('entity_id', $id)
->load()
->getFirstItem();
$product->setName($this->getRequest()->getParam('name'));
$product->setSku($this->getRequest()->getParam('sku'));
$product->setDescription($this->getRequest()->getParam('description'));
$product->setShortDescription($this->getRequest()->getParam('short_description'));
$product->setPrice($this->getRequest()->getParam('price'));
$product->setWeight($this->getRequest()->getParam('weight'));
$product->setStock($this->getRequest()->getParam('stock'));
$product->save();
if ( isset($_FILES) && count($_FILES) > 0 ) {
foreach($_FILES as $image ) {
if ( $image['tmp_name'] != '' ) {
if ( ( $error = $this->uploadImage($image, $id) ) !== true ) {
$errors[] = $error;
}
}
}
}
if ( empty($errors) ) {
$this->_getSession()->addSuccess($this->__('Your product was successfully updated'));
} else {
$this->_getSession()->addError('Product info was saved but was imposible to save the image');
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
}
$this->_redirect('customer/products/');
}
}
}
as well as a form that on submit is supposed to update the product attributes and images but the page reloads on submit and shows successful saved message but the attributes are not updated and going back to the edit form (for each product created) for that product the values in the update form have the values of the update we just submitted, bet yet the products attributes are not updated in the catalog either (they remain the same values as entered in the create new process)
don't no if to continue to figure out what is going wrong or just move to either use api or direct sql to get the job done.
see this post Magento 1.7: Non-system product attribute not saving in PHP script the problem maybe different but the solution can be found in that post
updated to a new action to call in .phtml see below as it seems to be updating the product data as needed, still wanting to improve..
called in form using /frontendname/editApprovedPost/
public function editApprovedPostAction() {
$id = $this->getRequest()->getParam('productid');
$idproduct = $this->getRequest()->getParam('product_id');
if ( $id !== false ) {
list($data, $errors) = $this->validatePost();
if ( !empty($errors) ) {
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
$this->_redirect('customer/products/edit/', array(
'id' => $id
));
} else {
- now added more php code to action (in this order) after the } else {...
require_once 'app/Mage.php';
then add admin store for frontend product updates...
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
then get the customer id...
$customerId = Mage::getSingleton('customer/session')->getCustomerId();
then use the forms product Id to get the Product Id to update...
$product = Mage::getModel('catalog/product')->load("".$idproduct."");
then use setName() to update/save the attribute value grabbed from the forms input value...
$product->setName($this->getRequest()->getParam('name'));//use whatever attributes need (only text and text area tested so far)
then save/update product data with...
$product->save();
then add to run through errors...
if ( empty($errors) ) {
$this->_getSession()->addSuccess($this->__('Your product was successfully updated'));
} else {
$this->_getSession()->addError('Product info was saved but was imposible to save the image');
foreach ($errors as $message) {
$this->_getSession()->addError($message);
}
}
$this->_redirect('customer/products/');
}
}
}
then with a form to submit in frontend with customer logged in and customer group config
custom form only visible to Customer Group 2 (default is Wholesale)
form below....
sorry cant paste form to much work to paste the code here, any way using the
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
which i have read in some posts is that to update product in frontend you need to be "admin", which this seems to do just fine. As Noted before, the script was not updating and it was because it is trying to save to a different models data when the data to be updated was an actual product (that has been approved and created using the different models data) and it was updating using
$product = Mage::getResourceModel('customerpartner/customerpartner_product_collection')
would be good to here anyone else's comments
hope this helps someone because was think time to close this build.

Youtube api get latest upload thumbnail

I am looking to returning the video-thumbnail of the latest uploaded video from my channel, and display it on my website.
Anyone know how I can do a minimal connection trough api and get only the thumbnail?
Thanks!
-Tom
REVISED!!
Using Cakephp, this is how I did it (thanks dave for suggestions using zend);
controller:
App::import('Xml');
$channel = 'Blanktv';
$url = 'https://gdata.youtube.com/feeds/api/users/'.$channel.'/uploads?v=2&max-results=1&orderby=published';
$parsed_xml =& new XML($url);
$parsed_xml = Set::reverse($parsed_xml);
//debug($parsed_xml);
$this->set('parsed_xml',$parsed_xml);
View;
$i=0;
foreach ($parsed_xml as $entry)
{
echo '<a href="/videokanalen" target="_self">
<img width="220px" src="'.$entry['Entry']['Group']['Thumbnail'][1]['url'] .'">
</a>';
}
Now the only thing remaining is to cache the feed call someway.. Any suggestions???
-Tom
here is a quick dirty way of doing it without really touching the api at all.
I'm not suggesting it's best practice or anything and I'm sure there are smarter ways but it definitely works with the current Youtube feed service.
My solution is PHP using the Zend_Feed_Reader component from Zend Framework, if you need a hand setting this up if you're not familiar with it let me know.
Essentially you can download version 1.11 from Zend.com here and then make sure the framework files are accessible on your PHP include path.
If you are already using Zend Framework in an MVC pattern you can do this in your chosen controller action:
$channel = 'Blanktv'; //change this to your channel name
$url = 'https://gdata.youtube.com/feeds/api/users/'.$channel.'/uploads';
$feed = Zend_Feed_Reader::import($url);
$this->view->feed = $feed;
Then you can do this in your view:
<h1>Latest Video</h1>
<div>
<?php
$i=0;
foreach ($this->feed as $entry)
{
$urlChop = explode ('http://gdata.youtube.com/feeds/api/videos/',$entry->getId());
$videoId = end($urlChop);
echo '<h3>' . $entry->getTitle() . '</h3>';
echo '<p>Uploaded on: '. $entry->getDateCreated() .'</p>';
echo '<a href="http://www.youtube.com/watch?v=' . $videoId .'" target="_blank">
<img src="http://img.youtube.com/vi/' . $videoId .'/hqdefault.jpg">
</a>';
$i++;
if($i==1) break;
}
?>
</div>
otherwise you can do:
<?php
$channel = 'Blanktv'; //change this to your channel
$url = 'https://gdata.youtube.com/feeds/api/users/'.$channel.'/uploads';
$feed = Zend_Feed_Reader::import($url);
?>
<h1>Latest Video</h1>
<div>
<?php
$i=0;
foreach ($feed as $entry)
{
$urlChop = explode ('http://gdata.youtube.com/feeds/api/videos/',$entry->getId());
$videoId = end($urlChop);
echo '<h3>' . $entry->getTitle() . '</h3>';
echo '<p>Uploaded on: '. $entry->getDateCreated() .'</p>';
echo '<a href="http://www.youtube.com/watch?v=' . $videoId .'" target="_blank">
<img src="http://img.youtube.com/vi/' . $videoId .'/hqdefault.jpg">
</a>';
$i++;
if($i==1) break;
}
?>
</div>
With the latter method you'll likely need to use a php require statement for the Zend_Feed_Reader files etc....
Hope this helps, like I say let me know if you need a hand.
All the best,
Dave
UPDATE: In response to your comments about caching
Hi Tom, here is another quick and dirty solution which doesn't use cache but may be very quick to implement.
The reason I didn't go with a caching component is because I figured a simple db solution would suffice under the circumstances. I also thought having to pull the feed to compare whether it was new or not wouldn't be the most economical for you.
You could automate this process to be run automatically at specified times but if you don't want to automate the process and don't mind clicking a link to update the video manually you could trigger it that way.
My solution is again based on ZF but since you were ok hacking it into something useful with cakephp you should have no problem doing the same here.
First set up a new table (assuming a MySQL db):
CREATE TABLE `yourdbname`.`latestvid` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT 'Unique identifier',
`videoId` VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Video id',
`videoTitle` VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Video title',
`uploadDate` VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Video upload date'
) ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci;
INSERT INTO `yourdbname`.`latestvid` (`id`, `videoId`, `videoTitle`, `uploadDate`) VALUES (NULL, '--', '--', '--');
This will create a table for your latest video info for use in your template however the default values I've set up will not work with your template for obvious reasons.
You could then do something similar to this:
public function updateAction()
{
$this->_helper->viewRenderer->setNoRender(); // disable view
$this->_helper->layout()->disableLayout(); // disable layout
$user = 'Blanktv'; // insert your channel name
$url = 'https://gdata.youtube.com/feeds/api/users/'.$user.'/uploads';
$feed = Zend_Feed_Reader::import($url);
if(!$feed)
{
die("couldn't access the feed"); // Note: the Zend component will display an error if the feed is not available so this wouldn't really be necessary for ZF
}
else
{
$i=0;
foreach ($feed as $entry)
{
$urlChop = explode ('http://gdata.youtube.com/feeds/api/videos/',$entry->getId());
$videoId = end($urlChop);
$videoTitle = $entry->getTitle();
$uploadDate = $entry->getDateCreated();
// use your preferred method to update the db record where the id = 1
$i++;
if($i==1) break;
}
}
}
Maybe have a go and let me know how you get on?
You'd just need to tweak the template so you'd get the variables from the database instead of Youtube with the exception of the thumbnail.
I suppose you could always take that approach further and actually store images etc since the thumbnail is still being pulled from Youtube and may slow things down.
You could set up a script to copy the thumbnail to your own server and store the path in the db or use a standard thumbnail if you are running a series of videos for which you require standard branding - anyway hope it helps.
:-D
Dave