I've had problem with ajax requests that my requests translating __() functions didn't work.
Googled it from everywhere.
Everywhere was as an answer that url parameter in the following form ?lang=fi should be added for the requests.
It turned out that if you are using Polylang your ajax requests url must in format /fi. Note for the default language this shouldn't be defined at all.
Solved the problem with this change.
I hope this helps someone.
I know am late to the party but I couldn't find any answers anywhere that will solve this problem and Libla's answer it's just right.
Just a little context:
I have a multilingual Woocommerce website and all translations were working great except for the checkout "order review" that is loading with Ajax.
This part after Ajax is showing in the website language (the one you have set up in settings).
All of that is because the Ajax call ignores the "?lang=" parameter (probably just the Polylang plugin, I never checked with other translation plugins).
Instead, Ajax should contain the language parameter (like in the browser www.yourwebsite.com/fi).
To solve that, I've added a filter (in functions.php)
/** Fix ajax handler translation */
add_filter( 'woocommerce_get_script_data', 'ajax_handler_fix_translation' );
if ( ! function_exists( 'ajax_handler_fix_translation' ) ) {
function ajax_handler_fix_translation( $params ) {
/** Get the current language */
$locale = determine_locale();
/** Take just the first part of the $locale */
$lang = ( ! empty( $locale ) ) ? strstr( $locale, '_', true ) : '';
if ( empty( $lang ) ) {
/** If there is no $lang parameter, just return to standard */
return $params;
}
if ( isset( $params['wc_ajax_url'] ) ) {
$params['wc_ajax_url'] = '/'.$lang.$params['wc_ajax_url'];
}
return $params;
}
}
Related
I would like add my own regular expression for validating the phone number. In my class-wc-validation.php I have changed the regular expression to my requirement.
public static function is_phone( $phone ) {
//if ( strlen( trim( preg_replace( '/[\s\#0-9_\-\+\(\)]/', '', $phone ) ) ) > 0 )
if ( strlen( trim( preg_replace( '/^[6789]\d{9}$/', '', $phone ) ) ) > 0 )
return false;
return true;
}
But the validation is not happening. What am I missing?
Was facing the same issue and followed what others had said here, but Woocommerce only sets the errors on validation after woocommerce_checkout_process hook.
But, in the latest Woocommerce 3.0 (not sure if this is in the 2.x version), we can use the woocommerce_after_checkout_validation hook and then look into the $data param if you are using the standard checkout fields or use $_POST if you have custom fields that aren't added in the standard Woocommerce way. An example of the code is:
public function validate($data,$errors) {
// Do your data processing here and in case of an
// error add it to the errors array like:
$errors->add( 'validation', __( 'Please input that correctly.' ));
}
add_action('woocommerce_after_checkout_validation', 'validate',10,2);
Hope that helps!
I have not seen your code that hooks these up to the woocommerce checkout flow.
please check their documentation on
woocommerce_checkout_process and woocommerce_checkout_order_processed
But in your case, I highly suggest that you hook it up on woocommerce_checkout_process
so put these codes below on your functions.php on your theme, or you create your own woocommerce plugins, and put it in the bootstrap code.
add_action('woocommerce_checkout_process', 'is_phone');
function is_phone() {
$phone_number = $_POST['---your-phone-field-name---'];
// your function's body above, and if error, call this wc_add_notice
wc_add_notice( __( 'Your phone number is wrong.' ), 'error' );
}
You should not edit plugin files, because if you update plugin all the
customization will be lost, rather you can use hook to achieve your
goal. You can use using woocommerce_checkout_process hook to do
this.
Here is the code:
add_action('woocommerce_checkout_process', 'wh_phoneValidateCheckoutFields');
function wh_phoneValidateCheckoutFields() {
$billing_phone = filter_input(INPUT_POST, 'billing_phone');
if (strlen(trim(preg_replace('/^[6789]\d{9}$/', '', $billing_phone))) > 0) {
wc_add_notice(__('Invalid <strong>Phone Number</strong>, please check your input.'), 'error');
}
}
Code goes in functions.php file of your active child theme (or theme). Or also in any plugin PHP files.
Please Note: By default WooCommerce use billing_phone field to take phone number, but if you have customized it then you can replace billing_phone with your field name.
Hope this helps!
In your question you're saying that validation rule is not working and I guess it's written in a wrong way. You can test it in online with regexp tools, e.g. Regex101 or others.
To answer more general on this topic, changing validation rules safely can be done this way:
Make a copy of class-wc-validation.php to your theme directory in your_theme_path/woocommerce/includes/class-wc-validation.php and make customization to the validation rules.
Then you should make a validation rule for the phone filed in checkout.js otherwise your field always will have green border despite it's invalid.
So my solution was to add custom regular expression validator to checkout.js about line 192:
if ( $parent.is( '.validate-phone' ) ) {
if ( $this.val() ) {
var pattern = new RegExp(/^([0-9\s\/\+\-\#\_\(\)]*)$/);
if ( ! pattern.test( $this.val() ) ) {
$parent.removeClass( 'woocommerce-validated' ).addClass( 'woocommerce-invalid woocommerce-invalid-phone' );
validated = false;
}
}
}
And include your customized .js file (in functions.php)
add_action( 'wp_enqueue_scripts', 'my_checkoutjs_enqueue_scripts', 100 );
function gv_checkoutjs_enqueue_scripts() {
if ( is_checkout() ) {
wp_deregister_script( 'wc-checkout' );
wp_enqueue_script( 'wc-checkout', get_template_directory_uri() . '/js/modified_checkout.js', array( 'jquery', 'woocommerce', 'wc-country-select', 'wc-address-i18n' ) );
}}
Hope this helps!
I was working on creating a WP plugin that will load other plugins only on specific URL. These plugins are deactivate in WP admin plugins, and are only loaded when a specific page is accessed.
Within my plugin's Class construct function:
$uri = $_SERVER['REQUEST_URI'];
$exp = explode('/', $uri);
$uri = $exp[2];
$options = get_option( $this->plugin_name );
$key = array_search( '/'.$uri.'/', array_column($options, 'url') );
$plugin_dir = $options[$key]['plugin']; // this prints plugin file directory ex. /MyPlugin/myplugin.php
include( WP_PLUGIN_DIR . $plugin_dir);
Above code loads the plugin on specific URL/page. Meaning the variable $plugin_dir grabbed the correct directory. BUT, problem occur when there's an AJAX request from that plugin. Ex. when i try to delete an item using ajax request, it returns Error 404 Bad request.
Weird part is, almost same code above, but this time, i manually assign the plugin directory to a variable: ex.
$uri = $_SERVER['REQUEST_URI'];
$exp = explode('/', $uri);
$uri = $exp[2];
$options = get_option( $this->plugin_name );
$key = array_search( '/'.$uri.'/', array_column($options, 'url') );
$plugin_dir = '/MyPlugin/myplugin.php'; // manually place the plugin file dir
//same output as $plugin_dir = $options[$key]['plugin'];
include( WP_PLUGIN_DIR . $plugin_dir);
But this time, plugin works really well. No Ajax bad request error.
What could be the possible explanation for this? Is there any solution about this issue, so that i can dynamically get the plugin file directory from wp options based on the Request URI.
Also, another issue. Instead of REQUEST URI, i wanted to get the POST/PAGE ID instead, but everything returns NULL/empty. Still inside the construct function, i tried different approach to get the page ID:
global $post;
var_dump($post->ID); //returns NULL
global $wp_query;
var_dump($wp_query->post->ID); //returns NULL
echo get_the_ID(); //returns empty/NULL
Is there a way how to properly get the POST/PAGE details, or even just the ID?
Thank you.
I have a simple custom form in Joomla 3.6 that I have added reCaptcha to successfully. However, I am struggling with validating this.
After a few web searches, I can up with the following code:
$joomla_captcha = JFactory::getConfig()->get('captcha');
if ( $joomla_captcha != '0') {
$jpost = JFactory::getApplication()->input->post;
$reCaptcha = $jpost->get("g-recaptcha-response");
$dispatcher = JEventDispatcher::getInstance();
$captcha_response = $dispatcher->trigger('onCheckAnswer', $reCaptcha);
}
if ( ! $captcha_response[0] ) {
die("Invalid Captcha");
}
However, the form is passing whether the captcha is done or not.
What changes do I need to make to pick up whether the captcha was passed or not?
The form is really basic and I am loathe to install yet another component just for this validation.
Okay, it appears I hit a brick wall in trying to find a "Joomla" way to do this that calls on inbuilt API methods.
Since I am only using Google reCaptcha, I found on Google's site that the "g-recaptcha-response" field is empty if the captcha challenge has not been completed and not empty if correctly completed.
So, for Google reCaptcha, I need to test the "g-recaptcha-response" field and my code example becomes:
$joomla_captcha = JFactory::getConfig()->get('captcha');
if ( $joomla_captcha != '0') {
$jpost = JFactory::getApplication()->input->post;
$reCaptcha = $jpost->get("g-recaptcha-response");
}
if ( isset( $reCaptcha ) && empty( $reCaptcha ) {
die("Invalid Captcha");
}
This is obviously limited to Google reCaptcha and would have been nice to query the Joomla API Layer instead to allow flexibility but good enough.
Edit
The following Joomla API calls will return "true" or "false" into $completed indicating whether the captcha passed or not
$config = JFactory::getConfig()->get('captcha');
$captcha = JCaptcha::getInstance($config);
$completed = $captcha->CheckAnswer();
if ($completed === false) {
die("Invalid Captcha");
}
Preferable to the earlier approach as will be able to work with other captcha plugins that may be added to Joomla.
Ok, so I've looked at many posts on here about similar topics, but every single one of them is a rewrite rule for an actual php file in the url such as cart.php rather than the pretty permalink /cart/.
Basically, all I'm trying to do here is have WordPress include a template whenever a specific url is visited. In this case, example.com/cart/. Since this code is for a plug-in, it's a url that does not exist, and I cannot create a page for it. I'm trying to use a rewrite rule, along with query vars, to display the correct template when the user visits /cart/. I think I'm pretty close, but I've tried it several different ways, and I know I'm probably missing something obvious. I keep getting a 404 error, and I'm pretty sure it's my rewrite rule that is the problem. Can you guys give me a hand with this one?
Code:
/* Rewrite Rules */
add_action('init', 'llc_product_rewrite_rule');
function llc_product_rewrite_rule() {
add_rewrite_rule( 'cart/', 'index.php?llc_page=cart', 'top' );
}
/* Query Vars */
add_filter( 'query_vars', 'llc_product_register_query_var' );
function llc_product_register_query_var( $vars ) {
$vars[] = 'llc_page';
return $vars;
}
/* Parse Request */
add_action('parse_request', 'llc_cart_template');
function llc_cart_template() {
if (get_query_var('llc_page') && (get_query_var('llc_page') == "cart")) {
include plugin_dir_path(__FILE__).'inc/cart.php';
exit();
}
return;
}
Thank you for all of your well thought out responses you guys, but unfortunately I don't have all day and had to go through trial and error hell to figure this one out.
So firstly, if you want to simply have example.com/cart/ load a specific page template, when the page does not exist (for example if you need your wordpress plug-in to generate the page), this is how you'll need to set up your code. To clarify what's different from the code in my question, it's the rewrite rule, and the way I included the template. I used template_include rather than parse_request.
/* Rewrite Rules */
add_action('init', 'llc_product_rewrite_rule');
function llc_product_rewrite_rule() {
add_rewrite_rule( 'cart/?$', 'index.php?llc_page=cart', 'top' );
}
/* Query Vars */
add_filter( 'query_vars', 'llc_product_register_query_var' );
function llc_product_register_query_var( $vars ) {
$vars[] = 'llc_page';
return $vars;
}
/* Template Include */
add_filter('template_include', 'llc_cart_template_include', 1, 1);
function llc_cart_template_include($template)
{
global $wp_query;
$llc_page_value = $wp_query->query_vars['llc_page'];
if ($llc_page_value && $llc_page_value == "cart") {
return plugin_dir_path(__FILE__).'inc/cart.php';
}
return $template;
}
In my codeigniter config I have $config['global_xss_filtering'] = TRUE;. In my admin section I have a ckeditor which generates the frontend content.
Everything that is typed and placed inside the editor works fine, images are displayed nice, html is working. All except flash. Whenever I switch to html mode and paste a youtube code piece it is escaped and the code is visible on the frontpage instead of showing a youtube movie.
If I set $config['global_xss_filtering'] = FALSE; the youtube code is passed like it should. This is because 'object', 'embed' etc are flagged as "naughty" by CI and thus escaped.
How can I bypass the xss filtering for this one controller method?
Turn it off by default then enable it for places that really need it.
For example, I have it turned off for all my controllers, then enable it for comments, pages, etc.
One thing you can do is create a MY_Input (or MY_Security in CI 2) like the one in PyroCMS and override the xss_clean method with an exact copy, minus the object|embed| part of the regex.
http://github.com/pyrocms/pyrocms/blob/master/system/pyrocms/libraries/MY_Security.php
It's one hell of a long way around, but it works.
Perhaps we could create a config option could be created listing the bad elements for 2.0?
My case was that I wanted global_xss_filtering to be on by default but sometimes I needed the $_POST (pst you can do this to any global php array e.g. $_GET...) data to be raw as send from the browser, so my solution was to:
open index.php in root folder of the project
added the following line of code $unsanitized_post = $_POST; after $application_folder = 'application'; (line #92)
then whenever I needed the raw $_POST I would do the following:
global $unsanitized_post;
print_r($unsanitized_post);
In CodeIgniter 2.0 the best thing to do is to override the xss_clean on the core CI library, using MY_Security.php put this on application/core folder then using /application/config.php
$config['xss_exclude_uris'] = array('controller/method');
here's the MY_Security.php https://gist.github.com/slick2/39f54a5310e29c5a8387:
<?php
/**
* CodeIgniter version 2
* Note: Put this on your application/core folder
*/
class MY_Security extends CI_Security {
/**
* Method: __construct();
* magic
*/
function __construct()
{
parent::__construct();
}
function xss_clean($str, $is_image = FALSE)
{
$bypass = FALSE;
/**
* By pass controllers set in /application/config/config.php
* config.php
* $config['xss_exclude_uris'] = array('controller/method')
*/
$config = new CI_Config;
$uri = new CI_URI;
$uri->_fetch_uri_string();
$uri->_explode_segments();
$controllers_list = $config->item('xss_exclude_uris');
// we need controller class and method only
if (!empty($controllers_list))
{
$segments = array(0 => NULL, 1 => NULL);
$segments = $uri->segment_array();
if (!empty($segments))
{
if (!empty($segments[1]))
{
$action = $segments[0] . '/' . $segments[1];
}
else
{
$action = $segments[0];
}
if (in_array($action, $controllers_list))
{
$bypass = TRUE;
}
}
// we unset the variable
unset($config);
unset($uri);
}
if ($bypass)
{
return $str;
}
else
{
return parent::xss_clean($str, $is_image);
}
}
}
Simple do the following on the views when displaying embedded object code like from YouTube and etc:
echo str_replace(array('<', '>'), array('<', '>'), $embed_filed);
The global XSS Filtering is only escaping (or converting) certain "dangerous" html tags like <html>
Simple Workaround:
Set $config['global_xss_filtering'] = TRUE;
Run your POST data through HTMLPurifier to remove any nasty <script> tags or javascript.
HTMLPurifier Docs
HTMLPurifier Codeigniter Integration
On the page where you receive the forms POST data use html_entity_decode() to undo what XSS filtering did.
//by decoding first, we remove everything that XSS filter did
//then we encode all characters equally.
$content = html_entity_decode($this->input->post('template_content'))
Then immediately run it through htmlentities()
$content = htmlentities($content);
Store as a Blob in MySQL database
When you want to display the
information to the user for editing run html_entity_decode()
This is how I did it. If anyone knows of a major flaw in what I did, please tell me. It seems to be working fine for me. Haven't had any unexpected errors.