Load HTML element with jQuery in DOM only if needed - javascript

I want to load a sidebar on desktop and hide it on mobile, but not only hide it: delete it fully, so that it's not loaded.
Before this, I tried using media queries and remove in jQuery, but in both of them, they are being loaded before they are hidden... So my solution now is to load a html only if I need them, but the problem is that I don't know how I have to do that.
Is this something like $("#containerDiv").append();?
I don't get it actually, because isn't this the same as removing it with jQuery or am I seeing it wrong? This ain't server side, right?

this not worked for you because you dont use <meta name="viewport" content="width=device-width, height=device-height" />(i say you in your previous question icheck this with my android phone)
in all solution your page must load after that javascript change page
you have 3 way
1:use media queries
2:use previous way load page check page size and remove object
3:use server side
in php
function check_user_agent ( $type = NULL ) {
$user_agent = strtolower ( $_SERVER['HTTP_USER_AGENT'] );
if ( $type == 'bot' ) {
// matches popular bots
if ( preg_match ( "/googlebot|adsbot|yahooseeker|yahoobot|msnbot|watchmouse|pingdom\.com|feedfetcher-google/", $user_agent ) ) {
return true;
// watchmouse|pingdom\.com are "uptime services"
}
} else if ( $type == 'browser' ) {
// matches core browser types
if ( preg_match ( "/mozilla\/|opera\//", $user_agent ) ) {
return true;
}
} else if ( $type == 'mobile' ) {
// matches popular mobile devices that have small screens and/or touch inputs
// mobile devices have regional trends; some of these will have varying popularity in Europe, Asia, and America
// detailed demographics are unknown, and South America, the Pacific Islands, and Africa trends might not be represented, here
if ( preg_match ( "/phone|iphone|itouch|ipod|symbian|android|htc_|htc-|palmos|blackberry|opera mini|iemobile|windows ce|nokia|fennec|hiptop|kindle|mot |mot-|webos\/|samsung|sonyericsson|^sie-|nintendo/", $user_agent ) ) {
// these are the most common
return true;
} else if ( preg_match ( "/mobile|pda;|avantgo|eudoraweb|minimo|netfront|brew|teleca|lg;|lge |wap;| wap /", $user_agent ) ) {
// these are less common, and might not be worth checking
return true;
}
}
return false;
}
this function check your agent call like below code
if(check_user_agent('mobile'))
{
echo 'mobile content';
}
else if(check_user_agent('browser'))
{
echo 'desktop content';
}

you can use below. Is it what you are looking.
if(// check if not mobile) {
// load the html or jsp
$( "#containerDiv" ).load( "ajax/test.html" );
}

Related

Handle WooCommerce selected variation custom field conditional display

I have this code where I need to insert a value based on a condition in: **///////// HERE THE MY CODE /////////**
Here I have overridden single-product/add-to-cart/variation.php Woocommerce template file via my active theme:
<script type="text/template" id="tmpl-variation-template">
<div class="woocommerce-variation-description">
{{{ data.variation.variation_description }}}
</div>
<div class="woocommerce-variation-price">
{{{ data.variation.price_html }}}
</div>
<div class="woocommerce-variation-custom_field">
{{{ data.variation.custom_field}}}
///////// HERE MY CODE /////////
</div>
<div class="woocommerce-variation-availability">
{{{ data.variation.availability_html }}}
</div>
</script>
The condition should check the value of the variable `{{{ data.variation.custom_field}}}` and if this data is greater than 10 then the code should print "Yes".
**Something like**:
if( $data.variation.custom_field > 10 ){
echo "yes";
}
But it's not working. I guess, this should be done using Javascript instead of php but I don't know how grab the variable value.
There is no need to use additional javascript (or jQuery) code for that.
The following will handle a product variation custom field displaying "YES" if the custom field value is bigger than 10 (otherwise nothing).
You will need to replace your exiting hooked function that use woocommerce_available_variation hook, with one of the following ways.
There are mainly 2 ways:
1). The simplest way, without overriding variation.php template:
// Frontend: Handle Conditional display and include custom field value on product variation
add_filter( 'woocommerce_available_variation', 'variation_data_custom_field_conditional_display', 10, 3 );
function variation_data_custom_field_conditional_display( $data, $product, $variation ) {
// Get custom field value and set it in the variation data array (not for display)
$data['custom_field'] = $variation->get_meta('custom_field');
// Defined custom field conditional display
$displayed_value = $data['custom_field'] > 10 ? 'YES' : '';
// Frontend variation: Display value below formatted price
$data['price_html'] .= '</div>' . $displayed_value . '
<div class="woocommerce-variation-custom_field_html">';
return $data;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
2). Another simple way (overriding variation.php template):
// Frontend: Handle Conditional display and include custom field value on product variation
add_filter( 'woocommerce_available_variation', 'variation_data_custom_field_conditional_display', 10, 3 );
function variation_data_custom_field_conditional_display( $data, $product, $variation ) {
// Get custom field value and set it in the variation data array (not for display)
$data['custom_field'] = $variation->get_meta('custom_field');
// Frontend display: Define custom field conditional display
$data['custom_field_html'] = $data['custom_field'] > 10 ? "YES" : "";
return $data;
}
Code goes in functions.php file of the active child theme (or active theme).
Then in your custom template single-product/add-to-cart/variation.php you will replace:
{{{ data.variation.custom_field}}}
with:
{{{ data.variation.custom_field_html }}}
It will work nicely without any additional requirements.
Here is a complete code example for the community, based on the 2nd Way:
1). Admin variations: Display a custom field and save it's value
// Admin: Add a custom field in product variations options pricing
add_action( 'woocommerce_variation_options_pricing', 'add_admin_variation_custom_field', 10, 3 );
function add_admin_variation_custom_field( $loop, $variation_data, $variation ){
woocommerce_wp_text_input( array(
'id' => 'custom_field['.$loop.']',
'label' => __('Custom Field', 'woocommerce' ),
'placeholder' => __('Enter Custom Field value here', 'woocommerce' ),
'desc_tip' => true,
'description' => __('This field is for … (explanation / description).', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'custom_field', true )
) );
}
// Admin: Save custom field value from product variations options pricing
add_action( 'woocommerce_save_product_variation', 'save_admin_variation_custom_field', 10, 2 );
function save_admin_variation_custom_field( $variation_id, $i ){
if( isset($_POST['custom_field'][$i]) ){
update_post_meta( $variation_id, 'custom_field', sanitize_text_field($_POST['custom_field'][$i]) );
}
}
Code goes in functions.php file of the active child theme (or active theme).
2). Frontend variations: Conditional display based on selected variation and custom field value
// Frontend: Handle Conditional display and include custom field value on product variation
add_filter( 'woocommerce_available_variation', 'variation_data_custom_field_conditional_display', 10, 3 );
function variation_data_custom_field_conditional_display( $data, $product, $variation ) {
// Get custom field value and set it in the variation data array (not for display)
$data['custom_field'] = $variation->get_meta('custom_field');
// Frontend display: Define custom field conditional display
$data['custom_field_html'] = $data['custom_field'] > 10 ? __("YES", "woocommerce") : "";
return $data;
}
Code goes in functions.php file of the active child theme (or active theme).
3). Template override: single-product/add-to-cart/variation.php file to your active theme's:
<?php
/**
* Single variation display
*
* This is a javascript-based template for single variations (see https://codex.wordpress.org/Javascript_Reference/wp.template).
* The values will be dynamically replaced after selecting attributes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #package WooCommerce/Templates
* #version 2.5.0
*/
defined( 'ABSPATH' ) || exit;
?>
<script type="text/template" id="tmpl-variation-template">
<div class="woocommerce-variation-description">{{{ data.variation.variation_description }}}</div>
<div class="woocommerce-variation-price">{{{ data.variation.price_html }}}</div>
<div class="woocommerce-variation-custom_field">{{{ data.variation.custom_field_html}}}</div>
<div class="woocommerce-variation-availability">{{{ data.variation.availability_html }}}</div>
</script>
<script type="text/template" id="tmpl-unavailable-variation-template">
<p><?php esc_html_e( 'Sorry, this product is unavailable. Please choose a different combination.', 'woocommerce' ); ?></p>
</script>
Tested and works.
Related: WooCommerce: Add/display Product or Variation custom field everywhere
Based on https://codex.wordpress.org/Javascript_Reference/wp.template and similar template engine like https://github.com/blueimp/JavaScript-Templates#evaluation, you need to build a template with evaluation.
In your case, it should be something like:
<div class="woocommerce-variation-custom_field">
<# if (data.variation.custom_field > 10) { #>
yes
<# } #>
</div>
Also, here https://lkwdwrd.com/wp-template-js-templates-wp you can find an example with if statement itself.

Dynamic Block - How to create dynamic stylesheet on post save / load

I've created a working Gutenberg Block with Create Guten Block (https://github.com/ahmadawais/create-guten-block).
Currently it's only working with inline-styles, but as a requirement I have to avoid them.
Therefore I want to create a post/page stylesheet when the post is saved including the style settings for my blocks (for example background-color, color, font-size...)
My block's current save function (block.js)
save: function( props ) {
const { attributes: { typetext, infotext, linktext, background_color, background_button_color, text_color, text_color_button }} = props;
return (
<div id="cgb-infoblock" className="cgb-infoblock">
<div className="cgb-infoblock-body" style={{
backgroundColor: background_color,
color: text_color,
}}>
<div className="cgb-infoblock-type">
<p>
<span className="cgb-infoblock-icon"><i>i</i></span>
{ typetext && !! typetext.length && (
<RichText.Content
tagName="span"
className={ classnames(
'cgb-infoblock-type-text'
) }
style={ {
color: text_color
} }
value={ typetext }
/>
)}
</p>
</div>
<div className="cgb-infoblock-text">
{ infotext && !! infotext.length && (
<RichText.Content
tagName="p"
style={ {
color: text_color
} }
value={ infotext }
/>
)}
</div>
</div>
<div className="cgb-infoblock-button" style={{
backgroundColor: background_button_color,
color: text_color_button,
}}>
{ linktext && !! linktext.length && (
<RichText.Content
tagName="p"
style={ {
color: text_color_button
} }
value={ linktext }
/>
)}
</div>
</div>
);
},
The best solution would be some sort of stylesheet generation for a whole page/post with all settings from all blocks.
Best way would be if the stylesheet generation is happening on page save, but it would be also ok if it is happening on page-load. Since those posts are not going to be large, the performance shouldn't be that much of a problem.
So after digging around I've figured it out myself.
Just in case someone else got this problem here's the solution:
First of all, attributes have to be defined in registerBlockTypefunction
registerBlockType( 'cgb/your-block-type', {
title: __( 'Your Block Name' ),
icon: 'shield',
category: 'maybe-a-category',
keywords: [
__( 'some keywords' ),
],
attributes: {
background_color: {
type: 'string',
default: 'default' //we will use the "default"-value later
},
},
So now Wordpress knows which attributes you wanna save. Problem now, as long as the "default" value is not overwritten, Wordpress won't save the value into the block object's attributes.
To solve this we'll use the save function from registerBlockType.
(Quick note on this: This will not trigger the default value for the editor widget, so you allways have to change your background_color's value to see it the first time you insert your widget into gutenberg editor. To fix this, use saveDefaultValue(this.props) right at the beginning of your render() function.)
save: function( props ) {
saveDefaultValues(props);
const { attributes: {background_color}} = props;
return (
//... here's your html that's beeing saved
);
},
function saveDefaultValues(props) {
if(props.attributes.background_color === 'default'){
props.attributes.background_color = '#f1f6fb';
}
}
With this we are forcing wordpress to save our default value. Pretty sure there's a better solution for this, but since I just started with react / Gutenberg, this is the only thing that got it working for me.
Ok, now we can save our Attributes into the Block-object.
Now we wanna create our dynamic stylesheet.
For this we are creating a new .php file in the following directory /plugin-dir/src/since we are using create-guten-block. The name doesn't matter, but I named it the same way like my stylesheet. `gutenberg-styles.css.php``
The gutenberg-styles.css.php will later create a gutenberg-styles.cssfile, everytime someone is visiting the post. But first we are looking into the plugin.phpfile.
Add the following code:
function create_dynamic_gutenberg_stylesheet() {
global $post;
require_once plugin_dir_path( __FILE__ ) . 'src/gutenberg-styles.css.php';
wp_enqueue_style('cgb/gutenberg-styles', plugins_url( 'src/gutenberg-styles.css', __FILE__ ));
}
add_action('wp_head', 'create_dynamic_gutenberg_stylesheet', 5, 0);
This code accesses the global $post variable, we need it to get all the gutenberg-blocks from the current visited post.
After that we require our own gutenberg-styles.css.php which will automatically create our stylesheet, which will be enqueued in the next line.
Now hook it up to wp_head(you could probably hook it up to wordpress save action as well, but you will have to do more work for enqueuing the stylesheet)
Finally a look into our gutenberg-styles.css.php:
$styleSheetPath = plugin_dir_path( __FILE__ ) . 'gutenberg-styles.css';
$styleSheet = '';
$blocks = parse_blocks($post->post_content);
//loop over all blocks and create styles
foreach($blocks as $block) {
$blockType = $block['blockName'];
$blockAttributes = $block['attrs']; //these are the attributes we've forced to saved in our block's save function
//switch case so you can target different blocks
switch ($blockType) {
case 'cgb/your-block-type':
$styleSheet .= '.your-block-class {'.PHP_EOL
$styleSheet .= 'background-color: '.$blockAttributes['background_color'].';'.PHP_EOL
$styleSheet .= '}'.PHP_EOL
break;
}
}
file_put_contents($styleSheetPath, $styleSheet); //write css styles to stylesheet (creates file if it not exists)
I've added PHP_EOL at each line to generate line breaks, you don't have to do this.
But now you can visit a page with your custom block and will see the gutenberg-styles.css is loaded and applied to your blocks.

Change "Sold out" for certain products in WooCommerce

What I am trying to do is to change the standard WooCommerce Sold Out message and add something after it for just two types of products.
I decided I could try do it with JavaScript by changing the text that appears in the p element when it appears. I first do a window url check to see if we are on the right page, and if we are, then make sure the text doesn't just say "UITVERKOCHT" but instead "UITVERKOCHT (neem contact op via contactformulier, levertijd 2 werkdagen)."
UITVERKOCHT shows when the product is sold out. But just for these two products, I want to add an extra message after UITVERKOCHT. So this is what I tried so far.
if(window.location.href.indexOf("prikkabel-50-meter") > -1 || window.location.href.indexOf("prikkabel-100-meter") > -1){
jQuery( "#product-5666 > div.single-product-wrapper > div.summary.entry-summary > form > div > div.woocommerce-variation.single_variation > div.woocommerce-variation-availability > p" ).change(function() {
console.log('a change occured');
});
}
Any idea what else I can try?
You could try the woocommerce_get_availability filter:
In your themes functions.php:
add_filter( 'woocommerce_get_availability', 'custom_availability', 5, 2 );
function custom_availability( $availability, $_product ) {
// If the product is out of stock and the product id = 5666
if ( ! $_product->is_in_stock() && $_product->id === 5666 ) {
$availability['availability'] = __( '[your custom text here]', 'woocommerce' );
}
return $availability;
}
This will apply the above filter if the product is out of stock AND the product id is 5666.

How to auto-populate sub-field selects from within a parent field

I'm using the ACF tutorial here to build from.
What I'd like to do is use the values in a text sub-field to populate other select sub-fields within the same repeater field. I know it sounds recursive and maybe that's prohibitive. The field admin will not be to ajax-y or update on the fly, it's more of an admin field for other site functionality.
Anyway, here's what I have so far.
ACF Repeater field = core_values
Page the field is on = valuesadmin
Source text sub-field within core_values = value_name
Target sub-fields (
each needing dynamically propagated selects from value_name) =
constructor1_name
constructor2_name
constructor3_name
destructor1_name
destructor2_name
I've tried to modify the code at the tutorial linked above and put it in the theme's functions.php and in the main file of a plugin I'm building other custom functions.
/**
* ACF population functions
*/
function acf_load_core_values_field_choices( $field ) {
// reset choices
$field['choices'] = array();
// if has rows
if( have_rows('core_values', 'valuesadmin') ) {
// while has rows
while( have_rows('core_values', 'valuesadmin') ) {
// instantiate row
the_row();
// vars
$value = get_sub_field('value_name');
$label = get_sub_field('value_name');
// append to choices
$field['constructor1_name'][ $value ] = $label;
$field['constructor2_name'][ $value ] = $label;
$field['constructor3_name'][ $value ] = $label;
$field['destructor1_name'][ $value ] = $label;
$field['destructor2_name'][ $value ] = $label;
}
}
// return the field
return $field;
}
add_filter('acf/load_field/name=constructor1_name', 'acf_load_core_values_field_choices');
add_filter('acf/load_field/name=constructor2_name', 'acf_load_core_values_field_choices');
add_filter('acf/load_field/name=constructor3_name', 'acf_load_core_values_field_choices');
add_filter('acf/load_field/name=destructor1_name', 'acf_load_core_values_field_choices');
add_filter('acf/load_field/name=destructor2_name', 'acf_load_core_values_field_choices');
Obviously this isn't propagating the select sub-fields as I'd like.
Questions:
- Is this even possible ( the value_name fields are all filled with values already )
- Where should the function code go?
- Maybe I've mangled the code somehow
Thanks in advance!
Well, I achieved the functionality I was looking for by first moving this all to an ACF options page and then creating another ACF field ( values_master) with which I could populate the values dynamically in a second field on the options page. So I'm not sure if this was not working because of some recursively but it IS working.
function acf_load_value_field_choices( $field ) {
// reset choices
$field['choices'] = array();
// if has rows
if( have_rows('values_master', 'option') ) {
// while has rows
while( have_rows('values_master', 'option') ) {
// instantiate row
the_row();
// vars
$value = get_sub_field('value_name');
$label = get_sub_field('value_name');
// append to choices
$field['choices'][ $value ] = $label;
}
}
// return the field
return $field;
}
add_filter('acf/load_field/name=constructor1_name', 'acf_load_value_field_choices');
add_filter('acf/load_field/name=constructor2_name', 'acf_load_value_field_choices');
add_filter('acf/load_field/name=constructor3_name', 'acf_load_value_field_choices');
add_filter('acf/load_field/name=destructor1_name', 'acf_load_value_field_choices');
add_filter('acf/load_field/name=destructor2_name', 'acf_load_value_field_choices');
add_filter('acf/load_field/name=value_mstr_name', 'acf_load_value_field_choices');

Adding JScript to a prestashop CMS page

prestashop v1.5.4.0
I want to add this click to open element made from CSS, HTML and JS located here http://codepen.io/anon/pen/Gqkxv
function openDoor(field) {
var y = $(field).find(".thumb");
var x = y.attr("class");
if (y.hasClass("thumbOpened")) {
y.removeClass("thumbOpened");
}
else {
$(".thumb").removeClass("thumbOpened");
y.addClass("thumbOpened");
}
}
what is the best method to place this in to a CMS page
My guess is since the CMS pages strip out most javascript tags and don't seem to allow you to attach exernal js files you will need to create an override of the cmsController.php.
You would need to create your external js file and css file and save them in the theme's js directory and css directory. The setMedia method is used to attach style/js files when that controller is called. You can override the cmsController.php and add this to the setMedia method
$this->addJS(_THEME_JS_DIR_.'yourjsfile.js');
$this->addCSS(_THEME_CSS_DIR_.'yourcssfile.css');
I believe that should work however, this will add these files to every cms page. The only way I can think to get around that is by getting the ID of the cms page(s) that you want it to appear on and run an if state on your addJS and addCSS functions.
example: You want it to show up on id_cms 4
if ((int)Tools::getValue('id_cms') == 4) {
$this->addJS(_THEME_JS_DIR_.'yourjsfile.js');
$this->addCSS(_THEME_CSS_DIR_.'yourcssfile.css');
}
or you want it to show on id_cms 4 and id_cms 6
if ((int)Tools::getValue('id_cms') == 4 || (int)Tools::getValue('id_cms') == 6) {
$this->addJS(_THEME_JS_DIR_.'yourjsfile.js');
$this->addCSS(_THEME_CSS_DIR_.'yourcssfile.css');
}
no need to add modules,
go to cms.tpl from your theme folder in prestashop,
add this
{if $cms->id==6}
{literal}
<script type="text/javascript" src="js/yourjsfile.js"></script>
{/literal}
{/if}
replace with your cms id and the name of your js file, then upload the file to js folder in prestahop root folder,
then go the prestahop panel, advanced parameters, performance, compile the templates and then launch your site --- the script will run only on the page selected
You can create a module and hook your js to backoffice header like this.
public function install()
{
if ( !$this->installTab()
|| !$this->registerHook('displayBackOfficeHeader'))
return false;
return true;
}
public function hookDisplayBackOfficeHeader()
{
//check if currently updatingcheck if module is currently processing update
if ($this->isUpdating() || !Module::isEnabled($this->name))
return false;
if (method_exists($this->context->controller, 'addJquery'))
{
$this->context->controller->addJquery();
$this->context->controller->addCss($this->_path.'views/css/gamification.css');
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === TRUE)
$this->context->controller->addJs($this->_path.'views/js/gamification_bt.js');
else
$this->context->controller->addJs($this->_path.'views/js/gamification.js');
$this->context->controller->addJqueryPlugin('fancybox');
return $css_str.'<script>
var ids_ps_advice = new Array('.rtrim($js_str, ',').');
var admin_gamification_ajax_url = \''.$this->context->link->getAdminLink('AdminGamification').'\';
var current_id_tab = '.(int)$this->context->controller->id.';
</script>';
}
}
This a example show from prestashop core module gamification. After that you can write your own prestashop js code which you want.
In 2019 regarding PS 1.7 - we solved it here: https://www.prestashop.com/forums/topic/267834-how-to-insert-javascript-code-inside-a-page/
In short - add it directly to CMS content field with slight modifiations:
1) in class/Validation.php add
public static function isCleanHtmlWithScript($html, $allow_iframe = false)
{
$events = 'onmousedown|onmousemove|onmmouseup|onmouseover|onmouseout|onload|onunload|onfocus|onblur|onchange';
$events .= '|onsubmit|ondblclick|onclick|onkeydown|onkeyup|onkeypress|onmouseenter|onmouseleave|onerror|onselect|onreset|onabort|ondragdrop|onresize|onactivate|onafterprint|onmoveend';
$events .= '|onafterupdate|onbeforeactivate|onbeforecopy|onbeforecut|onbeforedeactivate|onbeforeeditfocus|onbeforepaste|onbeforeprint|onbeforeunload|onbeforeupdate|onmove';
$events .= '|onbounce|oncellchange|oncontextmenu|oncontrolselect|oncopy|oncut|ondataavailable|ondatasetchanged|ondatasetcomplete|ondeactivate|ondrag|ondragend|ondragenter|onmousewheel';
$events .= '|ondragleave|ondragover|ondragstart|ondrop|onerrorupdate|onfilterchange|onfinish|onfocusin|onfocusout|onhashchange|onhelp|oninput|onlosecapture|onmessage|onmouseup|onmovestart';
$events .= '|onoffline|ononline|onpaste|onpropertychange|onreadystatechange|onresizeend|onresizestart|onrowenter|onrowexit|onrowsdelete|onrowsinserted|onscroll|onsearch|onselectionchange';
$events .= '|onselectstart|onstart|onstop';
if (!$allow_iframe && preg_match('/<[\s]*(i?frame|form|input|embed|object)/ims', $html)) {
return false;
}
return true;
}
2) then in /classes/CMS.php around line #66 change
'content' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtml', 'size' => 3999999999999)
to
'content' => array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isCleanHtmlWithScripts', 'size' => 3999999999999)
now you should be good to go

Categories