Including onclick action in href - woocommerce

I have a woocommerce webshop where i try to include an setAttribute('open', 'true') to a variation label.
However, it gives an error when returning the label:
Parse error: syntax error, unexpected 'open' (T_STRING) in .../shortcode.php on line 95
I changed the quotes for double quotes and vice versa but doesnt solve it.
add_filter( 'woocommerce_attribute_label' , 'modify_the_attribute_filter' , 10 , 3 );
function modify_the_attribute_filter( $label , $name , $product ){
$id = get_the_id();
if ( ($id ==189 || $id == 32 || $id == 754) && !is_admin() ){
if( $label == 'Lunch' ){
$label .= '<a class="extra_label" href="#anchor" onclick="det.setAttribute('open', 'true'); return false;">i</a>';
}
else {
$label .= '<a class="extra_label" href="#anchor">i</a>';
}
}
return $label;
}
The goal is that every variation label contains a clickable item that is an anchor to a point on the page and at the same time opens a details-summary box.

Have you tried to escape the quotes as following ?
$label .= '<a class="extra_label" href="#anchor" onclick="det.setAttribute(\'open\', \'true\'); return false;">i</a>';

Related

Remove Yoast Breadcrumb Last Item On Single Pages Only

i got this code from researching and trying to modify it but no luck. I want the last item in yoast breamcrumbs not to appear on single pages only
if ( is_single() ) {
/*Remove Last item in Yoast SEO Breadcrumb */
function adjust_single_breadcrumb( $link_output) {
if(strpos( $link_output, 'breadcrumb_last' ) !== false ) {
$link_output = '';
}
return $link_output;
}
add_filter('wpseo_breadcrumb_single_link', 'adjust_single_breadcrumb' );
};
I tried adding if is single in between the function and also this
if(strpos( $link_output, 'breadcrumb_last' ) !== false && is_single) {
unfortunately, the whole breadcrumb disappears.
with this code, you can remove post title in single page.
add_filter('wpseo_breadcrumb_single_link_info', 'remove_post_title_wpseo_breadcrumb', 10, 3);
function remove_post_title_wpseo_breadcrumb($link_info, $index, $crumbs)
{
if (is_singular() && isset($link_info['id']))
return [];
return $link_info;
}
Updated: In the latest version above code does not work perfectly.
for this reason, I removed the last item with regex:
function getBreadcrumb() {
if ( function_exists( 'yoast_breadcrumb' ) ) {
ob_start();
yoast_breadcrumb( '<p id="breadcrumb" class="meta-info">', '</p>' );
$breadcrumb = trim( ob_get_clean() );
if ( is_singular() )
$breadcrumb = trim( preg_replace( '/ ' . WPSEO_Options::get( 'breadcrumbs-sep' ) . ' <span class="breadcrumb_last" aria-current="page">(.*)<\/span>/i', '',
$breadcrumb ) );
echo $breadcrumb;
}
}
And call the function anywhere you want:
<?php getBreadcrumb() ?>

How to add a custom attribute?

How to add a custom attribute in the field Contact Form 7 without javascript ?
For example, there is such a field on the page:
<input type="text" name="name" class="form-control" id="name-1" data-attr="custom" data-msg="Текст 1">
Question: is it possible to set these custom attributes (data-attr, data-msg) of fields in the admin panel?
Find the name of your field.
[text* text-21]
If the name of your field name="text-21", like in my example, add this code to functions.php file.
add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' );
function imp_wpcf7_form_elements( $content ) {
$str_pos = strpos( $content, 'name="text-21"' );
if ( $str_pos !== false ) {
$content = substr_replace( $content, ' data-attr="custom" data-msg="Foo Bar 1" ', $str_pos, 0 );
}
return $content;
}
Note, it will add those attributes to all forms elements where the name is text-21, if you want prevent it then give your form element some unique name [text* unique-name]
And change the code to
add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' );
function imp_wpcf7_form_elements( $content ) {
$str_pos = strpos( $content, 'name="unique-name"' );
if ( $str_pos !== false ) {
$content = substr_replace( $content, ' data-attr="custom" data-msg="Foo Bar 1" ', $str_pos, 0 );
}
return $content;
}
Here is a generic solution that doesn't involve hardcoding the field name and the attributes
add_filter( 'wpcf7_form_tag', function ( $tag ) {
$datas = [];
foreach ( (array)$tag['options'] as $option ) {
if ( strpos( $option, 'data-' ) === 0 ) {
$option = explode( ':', $option, 2 );
$datas[$option[0]] = apply_filters('wpcf7_option_value', $option[1], $option[0]);
}
}
if ( ! empty( $datas ) ) {
$id = uniqid('tmp-wpcf');
$tag['options'][] = "class:$id";
add_filter( 'wpcf7_form_elements', function ($content) use ($id, $datas) {
return str_replace($id, $name, str_replace($id.'"', '"'. wpcf7_format_atts($datas), $content));
});
}
return $tag;
} );
It works on all data attributes so you can use it like this
[text* my-name data-foo:bar data-biz:baz placeholder "Blabla"]
Output: <input type="text" name="my-name" data-foo="bar" data-biz="baz" placeholder="Blabla">
Since wpcf7 doesn't provide a way to hook into options directly the solutions uses a trick and temporary adds a uniquely generated class to the field that is then replaced in a later filter with the added attributes
If you need it to work with more than just data attributes you can whitelist some more attributes by replacing this line
if ( strpos( $option, 'data-' ) === 0 ) {
to something like the following
if ( preg_match( '/^(data-|pattern|my-custom-attribute)/', $option ) ) {
Note: wpcf7_format_atts will not output empty attributes, so make sure you give a value to your attributes
Multiple attributes can be added also. eg
add_filter( 'wpcf7_form_elements', 'imp_wpcf7_form_elements' );
function imp_wpcf7_form_elements( $content ) {
$str_pos = strpos( $content, 'name="your-email-homepage"' );
$content = substr_replace( $content, ' aria-describedby="emailHelp" ', $str_pos, 0 );
$str_pos2 = strpos( $content, 'name="your-fname-homepage"' );
$content = substr_replace( $content, ' aria-describedby="fnameHelp" ', $str_pos2, 0 );
$str_pos3 = strpos( $content, 'name="your-lname-homepage"' );
$content = substr_replace( $content, ' aria-describedby="lnameHelp" ', $str_pos3, 0 );
return $content;
}
Extending on from Tofandel's solution, for the benefit of those who got 99% of the way there, but suffered validation issues - I've resolved that in my case and would like to offer an extended solution that gets as far as Tofandel's (putting the attribute into the form proper) but also successfully validates on submission.
add_filter('wpcf7_form_tag', function($tag) {
$data = [];
foreach ((array)$tag['options'] as $option) {
if (strpos( $option, 'autocomplete') === 0) {
$option = explode(':', $option, 2);
$data[$option[0]] = apply_filters('wpcf7_option_value', $option[1], $option[0]);
}
}
if(!empty($data)) {
add_filter('wpcf7_form_elements', function ($content) use ($tag, $data) {
$data_attrs = wpcf7_format_atts($data);
$name = $tag['name'];
$content_plus_data_attrs = str_replace("name=\"$name\"", "name=\"$name\" " . $data_attrs, $content);
return $content_plus_data_attrs;
});
}
return $tag;
} );
Rather than changing the tag ID to a random value only to replace it with the "real" value later, we just reference the real value in the first place, replacing the relevant part of the content in the wpcf7_form_elements filter (in my case, autocomplete, but as Tofandel's example shows, this can be extended to any data attribute you'd like).
I propose a solution from the one given by Tofandel without JS (CF7) error and to authorize the use of an attribute without value:
/**
* Add custom attributes on inputs
* Put "data-my-attribute" to use it, with or without value
*
* #param array $tag
*
* #return array
*/
function cf7AddCustomAttributes($tag) {
$datas = [];
foreach ((array) $tag['options'] as $option) {
if (strpos($option, 'data-') === 0 || strpos($option, 'id:') === 0) {
$option = explode(':', $option, 2);
$datas[$option[0]] = apply_filters('wpcf7_option_value', $option[1], $option[0]);
}
}
if (!empty($datas)) {
$id = $tag['name'];
if (array_key_exists('id', $datas)) {
$id = $datas['id'];
} else {
$tag['options'][] = "id:$id";
}
add_filter('wpcf7_form_elements', function ($content) use ($id, $datas) {
$attributesHtml = '';
$idHtml = "id=\"$id\"";
foreach ($datas as $key => $value) {
$attributesHtml .= " $key";
if (is_string($value) && strlen($value) > 0) {
$attributesHtml .= "=\"$value\"";
}
}
return str_replace($idHtml, "$idHtml $attributesHtml ", $content);
});
}
return $tag;
}
add_filter('wpcf7_form_tag', 'cf7AddCustomAttributes');
I use this simple method for setting attribute
[checkbox optName use_label_element "optName"]
<script>
document.querySelector(".optName").setAttribute("onchange","myscript");
</script>

Woocommerce - Display single product attribute(s) with shortcodes in Frontend

i've read many Q/A's here during the last few days, but unfortunately none of them solved my issue.
I'm trying to fetch product attributes and display them on the frontend with a shortcode. I have managed to display ALL available attributes and display them in a list, but i need to select only one or two of them in different locations (thats why using shortcodes). For example like [shortcode_attribute name="brand"].
Any help is highly appreciated!
my code so far:
function tutsplus_list_attributes( $product ) {
global $product;
global $post;
$attributes = $product->get_attributes();
if ( ! $attributes ) {
return;
}
foreach ( $attributes as $attribute ) {
// Get the taxonomy.
$terms = wp_get_post_terms( $product->id, $attribute[ 'name' ], 'all' );
$taxonomy = $terms[ 0 ]->taxonomy;
// Get the taxonomy object.
$taxonomy_object = get_taxonomy( $taxonomy );
// Get the attribute label.
$attribute_label = $taxonomy_object->labels->name;
// Display the label followed by a clickable list of terms.
echo get_the_term_list( $post->ID, $attribute[ 'name' ] , '<div><li class="bullet-arrow">' . $attribute_label . ': ' , ', ', '</li></div>' );
}
}
add_action( 'woocommerce_product_meta_end', 'tutsplus_list_attributes' );
add_shortcode('display_attributes', 'tutsplus_list_attributes');
While I am still not 100% clear what you're after, what I'm going to create is a shortcode that creates a list of all terms in all attributes. To make it more flexible I'll add support for a shortcode parameter so you can create a list of specific attribute terms.
One major thing you need to alter from your code, is that shortcodes need to RETURN a string and not ECHO out html. Echoing out shortcodes can result in unexpected weirdness.
/**
* Attributes shortcode callback.
*/
function so_39394127_attributes_shortcode( $atts ) {
global $product;
if( ! is_object( $product ) || ! $product->has_attributes() ){
return;
}
// parse the shortcode attributes
$args = shortcode_atts( array(
'attributes' => array_keys( $product->get_attributes() ), // by default show all attributes
), $atts );
// is pass an attributes param, turn into array
if( is_string( $args['attributes'] ) ){
$args['attributes'] = array_map( 'trim', explode( '|' , $args['attributes'] ) );
}
// start with a null string because shortcodes need to return not echo a value
$html = '';
if( ! empty( $args['attributes'] ) ){
foreach ( $args['attributes'] as $attribute ) {
// get the WC-standard attribute taxonomy name
$taxonomy = strpos( $attribute, 'pa_' ) === false ? wc_attribute_taxonomy_name( $attribute ) : $attribute;
if( taxonomy_is_product_attribute( $taxonomy ) ){
// Get the attribute label.
$attribute_label = wc_attribute_label( $taxonomy );
// Build the html string with the label followed by a clickable list of terms.
// Updated for WC3.0 to use getters instead of directly accessing property.
$html .= get_the_term_list( $product->get_id(), $taxonomy, '<li class="bullet-arrow">' . $attribute_label . ': ' , ', ', '</li>' );
}
}
// if we have anything to display, wrap it in a <ul> for proper markup
// OR: delete these lines if you only wish to return the <li> elements
if( $html ){
$html = '<ul class="product-attributes">' . $html . '</ul>';
}
}
return $html;
}
add_shortcode( 'display_attributes', 'so_39394127_attributes_shortcode' );
Usage: This would be used in 1 of 2 ways.
First, to display specific attributes use:
[display_attributes attributes="color|material"]
Second, to display all attributes use:
[display_attributes]
Edit
Here's an always single display edition:
/**
* Attribute shortcode callback.
*/
function so_39394127_singular_attribute_shortcode( $atts ) {
global $product;
if( ! is_object( $product ) || ! $product->has_attributes() ){
return;
}
// parse the shortcode attributes
$args = shortcode_atts( array(
'attribute' => ''
), $atts );
// start with a null string because shortcodes need to return not echo a value
$html = '';
if( $args['attribute'] ){
// get the WC-standard attribute taxonomy name
$taxonomy = strpos( $args['attribute'], 'pa_' ) === false ? wc_attribute_taxonomy_name( $args['attribute'] ) : $args['attribute'];
if( taxonomy_is_product_attribute( $taxonomy ) ){
// Get the attribute label.
$attribute_label = wc_attribute_label( $taxonomy );
// Build the html string with the label followed by a clickable list of terms.
// Updated for WC3.0 to use getters instead of directly accessing property.
$html .= get_the_term_list( $product->get_id(), $taxonomy, $attribute_label . ': ' , ', ', '' );
}
}
return $html;
}
add_shortcode( 'display_attribute', 'so_39394127_singular_attribute_shortcode' );
This removes all HTML markup, and so you'd need to provide your own... which would happen if you are making a custom list.
<ul>
<li class="arrow">Static List Item</li>
<li class="arrow">[display_attribute attribute="color"]</li>
<ul>
EDIT: This code can be added to your theme's functions.php, but preferably either in a site-specific plugin or via the Code Snippets plugin.
If anyone else just wants to simply output the attribute value as text, replace the $html .= line with this:
$html .= strip_tags(get_the_term_list($product->get_id(), $taxonomy));
#helgatheviking There must be a more elegant way than this! :)
Needed this recently - found https://wordpress.org/plugins/wcpas-product-attributes-shortcode/ does the trick.
With this plugin you can set an "attribute" parameter to match one of the product attributes you have setup.
For example if you have a brand attribute you can use:
[wcpas_product_attributes attribute="brand"]
This will output a <ul> list containing all brands.
There are also a number of parameters you can use alongside the attribute including:
orderby (order the list by an orderby value)
order (order asc, desc, rand, etc)
hide_empty (hide empty terms)
show_counts (show the total number of products in the brand)
archive_links (use an archive based URL instead of a filter based URL)
min_price (When using archive_links = 0 you can have a price filter based URL off a minimum price)
max_price (When using archive_links = 0 you can have a price filter based URL off a maximum price)

Place ads before last paragraph in wordpress

Here is the code for place ads after 1st, 2nd, 3d paragraph. but i want to place ad just before last paragraph of my wordpress post. is there any way to do this ?
<?php
add_filter( 'the_content', 'prefix_insert_post_ads' );
function prefix_insert_post_ads( $content ) {
$ad_code = '<div>Ads code goes here</div>';
if ( is_single() && ! is_admin() ) {
return prefix_insert_after_paragraph( $ad_code, 1, $content );
}
return $content;
}
// Parent Function that makes the magic happen
function prefix_insert_after_paragraph( $insertion, $paragraph_id, $content ) {
$closing_p = '</p>';
$paragraphs = explode( $closing_p, $content );
foreach ($paragraphs as $index => $paragraph) {
if ( trim( $paragraph ) ) {
$paragraphs[$index] .= $closing_p;
}
if ( $paragraph_id == $index + 1 ) {
$paragraphs[$index] .= $insertion;
}
}
return implode( '', $paragraphs );
}
?>
add_filter('the_content', 'ad_signal');
function ad_signal($content)
{
if (!is_single()) return $content;
$tent = get_the_content();
$content = explode("</p>", $content);
$ss = count($content);
$ns = $ss-1; //**before last paragraph in wordpress **
$new_content = '';
for ($i = 0; $i < count($content); $i++) {
if ($i == $ns ) {
$new_content.= ' <div style="text-align:center;">';
$new_content.= '<h1> Your ads Here ! </h1>';
$new_content.= '</div>';
}
$new_content.= $content[$i] . "</p>";
}
return $new_content;
}
I have set Adsense code by this Code in my sites named All BD Results and etunescafe. You just add this code in your sites functions.php N.B. Before adding the code please replace your or add your adsense code. It will be good enough to go through this post. How to Set Adsense Ads Right Before The Last Paragraph
function ads_added_above_last_p($text) {
if( is_single() ) :
$ads_text = '<div class="a" style="text-align: center;">Your Adsense Code</div>';
if($pos1 = strrpos($text, '<p>')){
$text1 = substr($text, 0, $pos1);
$text2 = substr($text, $pos1);
$text = $text1 . $ads_text . $text2;
}
endif;
return $text;
}
add_filter('the_content', 'ads_added_above_last_p');
Hey guys so I ran into the same problem and managed to solve it incorporating your answers into one.
The function that does all the processing is changed so that is counts all the paragraphs created by the explode method. Then another if statement is added to evaluate when you are at the desired location.
function prefix_insert_after_paragraph( $insertion, $paragraph_id, $content ) {
$closing_p = '</p>';
$paragraphs = explode( $closing_p, $content );
$last_paragraph_index = count($paragraphs);
foreach ($paragraphs as $index => $paragraph) {
if ( trim( $paragraph ) ) {
$paragraphs[$index] .= $closing_p;
}
if ( $paragraph_id == $index + 1 ) {
$paragraphs[$index] .= $insertion;
}
else if( $last_paragraph_index + $paragraph_id == $index + 1){
$paragraphs[$index] .= $insertion;
}
}
return implode( '', $paragraphs );
}
in order to use the new functionality you must call it with a negative number.
Think of the function this way, if you want to go from the top of the content you use a positive number, if you want to go from the bottom of the content you use a negative number.
Remember that even though the evaluation is for your decided spot such as before the last paragraph the condition that adds to the array uses the index which we all know is zero based.
This just means that to get after paragraph 1 you must use the number 2 when calling the function and to get to before the last paragraph you have to use -2 and so on.
Here is my example to add the a read the next post if it exists to the article
add_filter( 'the_content', 'prefix_insert_next_article_banner' );
function prefix_insert_next_article_banner( $content ) {
if ( is_single() && ! is_admin() && get_next_post_link() ) {
$next_banner = '<div class="next-banner"> <span> Read Next </span>';
$next_banner .= ' ' . get_the_title(get_adjacent_post(false,'',false)) .' ';
$next_banner .= '</div>';
return prefix_insert_after_paragraph( $next_banner, -2, $content );
}
return $content;
}

How-to get a menu label via $post-> or $page->ID

Entirely Revised Please Reread
Hello,
The theme I am using displays the page's title as opposed to it's menu label in the breadcrumbs. I am trying to get the breadcrumbs to instead display the associated menu label if it is available and if not then default to the page_title.
I have come up with some code that I think is close. Line 4/// $menu_items = wp_get_nav_menu_items( $slug ); returns null and it should return the nav item that contains $slug of the current post. Obviously, there is something I do not understand.
What I am attempting to do is get the slug of the current post, then using the slug get the nav item post. Then extract the title of the nav item and use that in place of the page title in the breadcrumbs. If the page was not in the nav system then it should default to the page title, as might be the case for a ppc campaign landing page.
if ( is_page() && !$post->post_parent ) {
$title = null;
$slug = mpactMEDIA_get_the_slug( get_the_ID() );
$menu_items = wp_get_nav_menu_items( $slug );
//var_dump((array)$menu_items);
foreach ( (array)$menu_items as $key => $menu_item ) {
$title = $menu_item->post_title;
}
if ( $title ) { echo $delimiter . ' ' . $before . $title . $after; }
else { echo $delimiter . ' ' . $before . get_the_title() . $after; }
}
I'm my functions.php file I have the following function
function mpactMEDIA_get_the_slug( $id=null ){
if( empty($id) ) global $post;
if( empty($post) ) return '';
$id = $post->ID;
endif;
$slug = basename( get_permalink($id) );
return $slug;
}
Thank you in advance,
Tim
I read the question a few times, I got here searching for an answer, ended up making my own.
function get_menu_label_by_post_id($post_id, $menu) {
$menu_title = '';
$nav = wp_get_nav_menu_items($menu);
foreach ( $nav as $item ) {
if ( $post_id == $item->object_id ) {
$menu_title = $item->post_title;
break;
}
}
return ($menu_title !== '') ? $menu_title : get_the_title($post_id);
}
Example usage:
echo get_menu_label_by_post_id($post->ID, 'Primary Nav');
This will return what the menu label is if it finds it, otherwise just the title of the post ID.
Check the documentation for wp_get_nav_menu_items. It doesn't take a page slug as a parameter at all.
If you want to list child pages of a given page, use wp_list_pages and pass a child_of parameter to it.
Also, as a side note, if you know the $post and want the slug, it's just $post->post_name

Resources