Favicon BulgaWeb

Suite à une question de Stéphane sur le groupe francophone Oxygen, j'ai fait une recherche pour faire fonctionner différents sliders Swiper dans des tabulations. Par défaut, le changement de tabulation casse le fonctionnement des sliders.

L'astuce que j'ai trouvée ici, a juste besoin d'être adaptée à Oxygen. Le code JS peut être gardé tel quel (en remplaçant juste la classe .tabInput par .oxytab) et nous allons juste adapter dans Oxygen.

new Swiper('.swiper-container', {
  navigation: {
    nextEl: '.swiper-button-next',
    prevEl: '.swiper-button-prev',
  }
});

let tabInputs = document.querySelectorAll('.oxy-tab');

tabInputs.forEach(function(input) {

  input.addEventListener('change', function() {
    let id = input.value;
    let thisSwiper = document.getElementById('swiper' + id);
    thisSwiper.swiper.update();
  });

});

Dans les tabulations nous allons rajouter un attribut "valeur" qui aura comme valeur une incrémentation en fonction du nombre de sliders (dans ce cas 1,2,3). Ensuite nous devrons changer l'ID du swiper-wrapper avec swiper1, swiper2, etc. Ainsi à chaque changement de tabulation, le slider sera mis à jour et fonctionnera correctement.

La structure de Swiper reste la même que sur ce tutoriel.

Vous pouvez voir ma démo sur cette page.

Un petit tutoriel complémentaire à la série Gsap de notre ami SupaMike (site). Gsap est une librairie JS qui permet de faire de nombreuses animations dans nos sites et il est possible de l'intégrer dans nos sliders Swiper.

Swiper peut interagir avec les évènements comme le changement de slide (slideChange) ce qui permet d'intégrer une animation dès que slide change. Plus d'informations sur ces propriétés sur cette section de la documentation.

Donc dès que les éléments contenus dans votre slider disposent d'une classe, vous lui appliquez l'animation de votre choix (voir la documentation de Gsap).

Dans mon slider de démonstration j'ai ajouté un déplacement vertical (donc axe Y) avec gsap.fromTo(".swip-title", 0.7, {y: "-200px"},{y: "0px"} ); sur mon titre et un déplacement horizontal sur le résumé (axe X) avec gsap.fromTo(".swip-text", 0.9, {x: "1200px"},{x: "0px"} );. Le code fromTo étant de -200px à 0px (position initiale).

Le code complet de ce simple exemple :

swiper.on("slideChange", function() {
  gsap.fromTo(".swip-title", 0.7, {y: "-200px"},{y: "0px"} );
  gsap.fromTo(".swip-text", 0.9, {x: "1200px"},{x: "0px"} );
});

Vous trouverez également beaucoup des sources YouTube ou Codepen avec d'autres exemples comme ceux-ci. Exemple 1, exemple 2, exemple 3.

Ma démonstration est ICI. Et l'intégration de Swiper ICI. Amusez-vous bien 😉

Suite à mon article sur l'utilisation globale de Pods avec Oxygen, je rajoute quelques astuces utiles ...

Ouvrir (télécharger) un pdf avec un bouton

En premier nous devrons créer un champ "fichier" et dans ce cas le restreindre au format PDF.

Ayant essayé de récupérer le lien du fichier dans le bouton, je me suis aperçu que je récupérais un tableau. En regardant de plus près, je devais récupérer le ["guid"] qui contient le lien du fichier. Je me suis donc inspiré de l'article de Mohammed Wasim Akram et des codes de Kevin Pauls and Matt Hias membres du groupe anglophone pour créer cette fonction :

function oxychild_pdf($field_name) {
			$mypod = pods( $post->post_type, $post->ID );	  
			$pop = $mypod->field($field_name);
			return $pop["guid"];
		}

Une fois avoir insérer cette fonction dans un plug-in, code snippets ou équivalant, vous pouvez récupérer le lien en utilisant le retour d'une fonction (nom de la fonction en premier et nom du champ ensuite) comme ceci :

Maintenant tout ça est bien sympa, mais j'aimerais que l'utilisateur puisse télécharger directement le fichier. Nous allons donc le faire en deux étapes, la première sera de rajouter la classe .download-button (ou toute autre à votre choix pour autant qu'elle corresponde dans le script) et rajouter ce script pour forcer le téléchargement :

jQuery(document).ready(function() {
  var downloadButton = jQuery('.download-button');
     
  downloadButton.each(function(index) {
    jQuery(this).attr('download', '');
  });
});

Utilisation des templates Pods

Par défaut, avec un thème classique WordPress, Pods permet de créer des templates (activé par défaut) qui utilisent les Magic Tags de Pods. Nous pouvons comparer ceci à un code bloc d'Oxygen. Il nous est donc possible d'utiliser le code court du template Pods dans une page créée avec Oxygen, l'avantage pouvant être de créer un équivalent d'un "reusable parts" et également utiliser la simplicité des codes courts de Pods. Voici une vidéo de présentation (en anglais) sur cet usage. Voir cette documentation.

Ajout d'article en frontend

Pods permet aussi de faire des formes pour ajouter ou éditer un article en frontend. Voir cette documentation.

Récupérer une image d'un champ multiple

Sur le groupe anglophone, un collègue a demandé s'il était possible de récupérer la première image d'un champ image multiple. L'idée étant de ne pas créer un deuxième champ pour une image en avant, par exemple, qui serait la première image d'une galerie. Comme ce champ est un tableau (array) nous pouvons récupérer l'image grâce à sa position dans le tableau. Récupérer le tableau dans une variable et cibler l'élément à récupérer (pour rappel un tableau commence à la valeur 0). Le code sera donc comme ceci pour la première image :

<?php
// get pods object
$mypod = pods( $post->post_type, $post->ID );

if ($mypod->field('property_slider')) {
  echo '<h3>Gallery:</h3>';
  echo '<div class="gallery-single">';
	foreach( $mypod->field('property_slider', true) as $picture) {
		echo '<div class="gal-single"><a href="' . $picture['guid'] . '" data-fancybox="gallery"><img src="' . $picture['guid'] . '" width="150" height="150" class="attachment-thumbnail size-thumbnail" alt="" /></a></div>';
	}
  echo '</div>';
$test = $mypod->field('property_slider', true);
}
<img src="<?php echo $test[0]['guid'];?>" alt="image" />

Pagination avec Pods

Pods possède ces propres fonctions pour la pagination. Attention la pagination fonctionne avec les modules Easypost et Repeater. Par défaut, WordPress utilise la valeur par défaut dans les préférences de lecture, mais il possible de changer ces valeurs suivant des conditions (deuxième code). Globalement nous devrons ajouter ceci :

<?php
$params = array( 
  	'limit' => 4,
    'orderby' => 't.post_title ASC',
);
$pods = pods( 'video', $params );

// Get the items, search is automatically handled
//$pods->find(); 

if ( $pods->total() > 0 ) {
    while( $pods->fetch() )  {
        //reset id
        $pods->id = $pods->id();    
        //get the template
        $temp = $pods->template( 'lifestream' );
        //output template if it exists
        if ( isset( $temp )  ) {       
            echo '<div class ="life-content">' . $temp . '</div>';
        }
    }
    //pagination
    echo $pods->pagination();
}
else {
    echo 'No content found.';
} 
?>

Dans certains cas où vous voudriez des paginations différentes, il faudra rajouter une fonction dans le functions.php. Voici les informations du codex et voici un exemple (CPT Properties et Agents, attention curieusement ce ne sont pas les slugs) :

function my_post_queries( $query ) {
  // do not alter the query on wp-admin pages and only alter it if it's the main query
  if (!is_admin() && $query->is_main_query()){

    // alter the query for the home and category pages 

    if(is_home()){
      $query->set('posts_per_page', 3);
    }

    // alter the query for the Movies category page 
    if(is_category('Properties')){
      $query->set('posts_per_page', 6);
    }
	  // alter the query for the Movies category page 
    if(is_category('Agents')){
      $query->set('posts_per_page', 4);
    }
  }
}
add_action( 'pre_get_posts', 'my_post_queries' );

à suivre ...

MISE A JOUR - Après de nombreux soucis avec une version PRO et leur add-on WooCommerce, je déconseille vivement l'achat de ce plugin qui n'est pas à la hauteur. Après moins d'un an, de nombreux bugs sont arrivés rendant la gestion très difficile et le support est insupportable. - "As I explain that to you, currently making the MEC compatible with Oxygen builder is not a high priority task for our dev team and our dev team will check this issue to make it compatible in the future which I can't give you an exact ETA for it."

J'ai découvert dernièrement le plug-in MEC que je préfère par rapport Events Calendar (personnel) et j'ai donc décidé de faire la migration pour un client. À noter que le plug-in possède des fonctions d'import, et ce, également pour récupérer les événements de Events Calendar (et d'autres).

La configuration est assez simple après avoir un peu cherché sur le fonctionnement du plug-in. Pour les archives il suffit de choisir un des nombreux modèles proposés par le plug-in et visibles sur leurs démos.

Dans l'administration, se rendre dans l'onglet shortcodes de MEC et sélectionner le modèle désiré et le copier-coller dans un élément shortcode d'Oxygen avec une taille de 100%.

Pour la page des événements, qui normalement est chargée via un thème, il faudra copier de contenu du template single dans un code bloc ce qui nous donnera ceci

<section id="<?php echo apply_filters('mec_single_page_html_id', 'main-content'); ?>" class="<?php echo apply_filters('mec_single_page_html_class', 'mec-container'); ?>">
            
	<?php do_action('mec_before_main_content'); ?>
            
            <?php while(have_posts()): the_post(); ?>

                <?php $MEC = MEC::instance(); echo $MEC->single(); ?>

            <?php endwhile; // end of the loop. ?>
            <?php //comments_template(); ?>

  
</section>

<?php do_action('mec_after_main_content'); ?>

Le template single seront configurés en fonction du CPT événements. Concernant la modification du contenu, il faudra se rendre dans les paramètres de MEC et sélectionner "Style de la page d'événements".

Beaucoup d'autres options de personnalisation sont disponibles avec le plug-in.

À noter que si vous êtes plus expérimenté, vous pourrez créé un "faux" thème enfant (sans css ni fonctions) et y ajouter un dossier webnus et y insérer vos propres templates personnalisés. Il faudra dans ce cas également utilisé oxythemenabler pour avoir accès à ce dossier.

Un petit défi pour un collègue australien. Il avait le plug-in Brands pour WooCommerce mais nous aurions aimé pouvoir filtrer sur les marques ainsi que d'avoir des archives par marques.

Dans un premier temps, nous allons créer l'attribut "Brands" ou "Marques" dans WooCommerce et nous allons cocher "Activer les archives"

Ensuite nous allons installer le plug-in Taxonomy Images et aller activer sur "Produit Brands".

J'ai ensuite créer une simple page Brands ou Marques et ajouter sur celle-ci un code bloc avec :

<?php
    $args = array(
        'taxonomy'    => 'pa_brands',
        'term_args'   => array(
            'hide_empty'    => false,
        )
    );
    $terms = apply_filters( 'taxonomy-images-get-terms', '', $args );

    foreach ($terms as $term){
        $archive_link = get_term_link( $term->slug, 'pa_brands' );
        $image_attributes = wp_get_attachment_image_src( $term->image_id, 'thumbnail' );

        $html = '<div class="mr-brand"><a href="' . $archive_link . '">'; 
        $html .= '<option>' . $term->name . '</option>';
   
        if ( $image_attributes ) { 
        $html .= '<img src="' . $image_attributes[0] . '" width="' . $image_attributes[1] . '" height="' .$image_attributes[2] . '" />';
        } 
        $html .= '</div></a>';
        
        echo $html;
    }    
?>

Nous récupérons donc toutes nos marques à l'intérieur d'une div qui a le lien vers l'archive de la marque ainsi que l'image que nous avons pu insérer avec le plug-in.

N'oubliez pas de faire un template ou de configurer votre template de catégorie sur cette taxonomie. Petite note : l'utilisation des taxonomies d'attributs dans WooCommerce doit être précédées de pa_.

Pour terminer nous allons peut-être aussi vouloir récupérer nos marques sur les produits (single). Voici la fonction à utiliser dans un bloc de code :

<?php
	global $product;
    $rmbrands = $product->get_attribute( 'pa_brands' );
    echo '<div class="rm-brands">Brand: ' . $rmbrands . '</div>';

	$mytaxonomy = 'pa_brands';
	$post_id = get_the_ID();
	$terms = wp_get_post_terms( $post_id, $mytaxonomy ); // Terms for this post
	$custom_taxonomy_images = get_option( 'taxonomy_image_plugin' ); // Plugin images data
	if ( empty( $terms ) ) return; // If no terms found, we exit.

	echo '<div class="rm-brands-container">';
	// Loop through each term in this post for the defined taxonomy
	foreach( $terms as $term ) {
		$attachment_id = $custom_taxonomy_images[intval($term->term_id)]; // Get image Attachement ID
		$image = wp_get_attachment_image( $attachment_id, 'thumbnail' ); // Get image to be displayed
		$url = get_term_link( $term->term_id, $taxonomy ); // Get term URL
 		?>
		<div class=”rm-brands-image”>
		<a href="<?php echo $url; ?>"><?php echo $image; ?>
		</div>
		<?php
		}
	echo '</div>';
?>

Quelques snippets utiles pour WooCommerce

Certaines sources viennent du très bon site BusinessBloomer

Ajouter des notifications d'erreur de champ en ligne

/**
 * @snippet       Remove Add Cart, Add View Product @ WooCommerce Loop
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @testedwith    WooCommerce 3.6.2
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
  
// First, remove Add to Cart Button 
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
  
// Second, add View Product Button
add_action( 'woocommerce_after_shop_loop_item', 'bbloomer_view_product_button', 10 );
  
function bbloomer_view_product_button() {
    global $product;
    $link = $product->get_permalink();
    echo '<a href="' . $link . '" class="button addtocartbutton">Details</a>';
}

Remplacer "Ajouter un panier" par "Voir le produit"

/**
 * @snippet       Remove Add Cart, Add View Product @ WooCommerce Loop
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @testedwith    WooCommerce 3.6.2
 * @donate $9     https://businessbloomer.com/bloomer-armada/
 */
  
// First, remove Add to Cart Button  
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
  
// Second, add View Product Button
add_action( 'woocommerce_after_shop_loop_item', 'bbloomer_view_product_button', 10 );
  
function bbloomer_view_product_button() {
    global $product;
    $link = $product->get_permalink();
    echo '<a href="' . $link . '" class="button addtocartbutton">Details</a>';
}

Afficher "épuisé" sur les pages en boucle

/**
 * @snippet       Display "Sold Out" on Loop Pages - WooCommerce
 * @how-to        Get CustomizeWoo.com FREE
 * @sourcecode    https://businessbloomer.com/?p=17420
 * @author        Rodolfo Melogli
 * @testedwith    WooCommerce 3.4.3
 */
 
add_action( 'woocommerce_before_shop_loop_item_title', 'bbloomer_display_sold_out_loop_woocommerce' );
 
function bbloomer_display_sold_out_loop_woocommerce() {
    global $product;
    if ( !$product->is_in_stock() ) {
        echo '<span class="soldout">' . __( 'SOLD OUT', 'woocommerce' ) . '</span>';
    }
} 

CSS :

.soldout {
    padding: 3px 8px;
    text-align: center;
    background: #222;
    color: white;
    font-weight: bold;
    position: absolute;
    top: 6px;
    right: 6px;
    font-size: 12px;
}

Afficher les sous-catégories de produits

/**
 * @snippet       WooCommerce Show Product Subcategories
 * @how-to        Get CustomizeWoo.com FREE
 * @sourcecode    https://businessbloomer.com/?p=17525
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 3.4.5
 */
 
add_action( 'woocommerce_after_shop_loop_item_title', 'bbloomer_show_all_subcats', 2 );
  
function bbloomer_show_all_subcats() {
    global $post;        
    $cats = get_the_terms( $post->ID, 'product_cat' );           
    if ( ! empty( $cats ) ) {                
        foreach ( $cats as $term ) {           
            // If parent 116 === cat ID echo subcat name...
            if ( 116 === $term->parent ) { 
                echo $term->name;
            }             
        }
    }        
}

En cours d’élaboration, doit être vérifié et complété !

Vous pouvez retrouvez des références ici Hooks et ici pour les produits seuls

Titre

<?php
global $product;
$product = wc_get_product( id );  //archive seulement
echo '<div class="woo-title"><h2>' . $product->get_title() . '</h2></div>';
?>

Permaliens

echo 'Lien : ' . get_permalink( $product->get_id() ) ;

Image principale

ATTENTION dans ce cas les badges ne sont pas récupérés

<?php
the_post_thumbnail(); // Without parameter ->; Thumbnail
the_post_thumbnail( 'thumbnail' ); // Thumbnail (default 150px x 150px max)
the_post_thumbnail( 'medium' ); // Medium resolution (default 300px x 300px max)
the_post_thumbnail( 'medium_large' ); // Medium-large resolution (default 768px x no height limit max)
the_post_thumbnail( 'large' ); // Large resolution (default 1024px x 1024px max)
the_post_thumbnail( 'full' ); // Original image resolution (unmodified)
the_post_thumbnail( array( 100, 100 ) ); // Other resolutions (height, width)
?>

Galerie

Fonction avec divers mode de récupération des images de la galerie d'un produit. Intégration assez aisée avec Swiper (à venir).

<?php
  global $product;
 $attachment_ids = $product->get_gallery_attachment_ids();

foreach( $attachment_ids as $attachment_id ) 
{
  //Get URL of Gallery Images - default wordpress image sizes
  echo $Original_image_url = wp_get_attachment_url( $attachment_id );
  echo $full_url = wp_get_attachment_image_src( $attachment_id, 'full' )[0];
  echo $medium_url = wp_get_attachment_image_src( $attachment_id, 'medium' )[0];
  echo $thumbnail_url = wp_get_attachment_image_src( $attachment_id, 'thumbnail' )[0];
  
  //Get URL of Gallery Images - WooCommerce specific image sizes
  echo $shop_thumbnail_image_url = wp_get_attachment_image_src( $attachment_id, 'shop_thumbnail' )[0];
  echo $shop_catalog_image_url = wp_get_attachment_image_src( $attachment_id, 'shop_catalog' )[0];
  echo $shop_single_image_url = wp_get_attachment_image_src( $attachment_id, 'shop_single' )[0];
  
  //echo Image instead of URL
  echo wp_get_attachment_image($attachment_id, 'full');
  echo wp_get_attachment_image($attachment_id, 'medium');
  echo wp_get_attachment_image($attachment_id, 'thumbnail');
  echo wp_get_attachment_image($attachment_id, 'shop_thumbnail');
  echo wp_get_attachment_image($attachment_id, 'shop_catalog');
  echo wp_get_attachment_image($attachment_id, 'shop_single');
}
?>

Récupérer les catégories des produits

global $product;

$product_cats_ids = wc_get_product_term_ids( $product->get_id(), 'product_cat' );
foreach( $product_cats_ids as $cat_id ) {
    $term = get_term_by( 'id', $cat_id, 'product_cat' );

    echo $term->name;
}

Insérer un attribut

function oxychild_woo_attribute(){
    global $product;
    $bui = $product->get_attribute( 'pa_pena' );
    echo '<div class="bu1_attribute">' . $bui . '</div>';
}
//add_action( 'woocommerce_shop_loop_item_title', 'bui_woo_attribute', 05 );
//add_action('woocommerce_single_product_summary', 'cw_woo_attribute', 25);

Il arrive dans certains cas que l'utilisation des éléments WooCommerce d'Oxygen ne suffisent pas pour nos besoins. Néanmoins il existe des solutions pour personnaliser nos modèles de pages WooCommerce grâce aux hook pour WooCommerce.

Il existe deux types de hook: les actions et les filtres. L'action vous permet d'ajouter du code personnalisé à différents endroits. Le filtre, en revanche, vous permet de manipuler, de remplacer et de renvoyer une nouvelle valeur de variable à la fin.

Si vous souhaitez utiliser un hook pour modifier ou ajouter un code personnalisé, vous pouvez l'ajouter dans le fichier functions.php d'OxyChild ou autre. L'utilisation avec le plugin Code Snippets est également possible sous forme de snippet avec l'avantage d'activer et désactiver plus simplement.

Si vous souhaitez modifier ou ajouter un code, vous devez d'abord aller dans le dossier du plugin. Vous pouvez le faire en accédant à woocommerce / templates / archive-product.php. Une fois que vous y êtes, vous devez vérifier les hooks que les auteurs du plugin ont implémentés ici.

Un bon lien pour visualiser l'archive des produits : https://www.businessbloomer.com/woocommerce-visual-hook-guide-archiveshopcat-page/

Comment supprimer le fil d'ariane

Le code personnalisé ci-dessous supprime la fonction woocommerce_breadcrumb qui ajoute un balisage de fil d'Ariane. Nous avons défini la priorité sur 20, car il s'agit d'une valeur de priorité par défaut dans le fichier de modèle de plug-in.

/**
* Hook: woocommerce_before_main_content.
*
* @hooked woocommerce_output_content_wrapper - 10 (outputs opening divs for the content)
* @hooked woocommerce_breadcrumb - 20
* @hooked WC_Structured_Data::generate_website_data() - 30
*/
do_action( 'woocommerce_before_main_content' );

Et maintenant, nous devons définir le même afin de supprimer cette zone.

// Remove breadcrumbs
remove_action( 'woocommerce_before_main_content', 'woocommerce_breadcrumb', 20 );

Comment masquer le titre de la page

if ( ! function_exists( 'hide_woocommerce_page_title' ) ) {
/**
* Hide WooCommerce page title
*/
function hide_woocommerce_page_title() {
return false;
}
add_filter( 'woocommerce_show_page_title', 'hide_woocommerce_page_title' );
}

Comment modifier le nombre de produits pour la page de la boutique

if ( ! function_exists( 'change_woocommerce_products_per_page' ) ) {
/**
* Change number of products on main shop page
*/
function change_woocommerce_products_per_page() {
return 8;
}
add_filter( 'loop_shop_per_page', 'change_woocommerce_products_per_page', 20 );
}

Comment changer les positions des prix et des notes

Pour changer la position des éléments dans un certain balisage (dans ce cas, un article de produit), vous pouvez utiliser les fonctions remove_action et add_action avec des priorités. Si des éléments sont ajoutés avec le hook, les priorités définissent l'endroit où l'élément sera à l'intérieur du balisage. La priorité inférieure rendra cet élément comme le premier.

Le plugin WooCommerce a beaucoup de hooks et dans la plupart des cas, les éléments sont ajoutés avec les hooks. Par conséquent, cet article est une occasion idéale de vous montrer comment vous pouvez également le faire.

Ici, nous allons vous montrer comment changer la position des éléments de prix et de notation. Le code pour cela sera:

// Remove functions from woocommerce_after_shop_loop_item_title hook with original priority
remove_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_rating', 5 );
remove_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10 );
// Added functions to woocommerce_after_shop_loop_item_title hook with new priority
add_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_rating', 10 );
add_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 5 );

Tout d'abord, nous supprimerons les deux éléments de la partie article du produit avec les fonctions et les priorités d'origine. Vous pouvez trouver les deux éléments dans le fichier content-product.php.

/**
* Hook: woocommerce_after_shop_loop_item_title.
*
* @hooked woocommerce_template_loop_rating - 5
* @hooked woocommerce_template_loop_price - 10
*/
do_action( 'woocommerce_after_shop_loop_item_title' );

Ensuite, nous ajouterons les mêmes fonctions sur le même hook avec de nouvelles priorités.

Liens de sources d'un article an anglais : https://wpklik.com/wordpress-tutorials/woocommerce-hooks/

Et avec Oxygen ?

Après avoir vu grâce à cet article les hook et leurs usages, nous allons pouvoir les utiliser dans Oxygen, sous forme de snippet/fontions ou dans des blocs de code, voir les modifier. Voici un exemple de snippet permettant d'afficher les dimensions d'un produit en dessous du titre sur la page d'archive (dans ce cas les produits étant des tableaux, nous voulons informer l'acheteur de la taille de celui-ci) ...

function taille_woo_attribute(){
    global $product;   
	$product_width = $product->get_width();
	$pruduct_length = $product->get_length();
	$product_dimensions = $product->get_dimensions();
	if (!empty($product_width) && !empty($product_length)) {
    echo '<div class="size_art">' . $product_length . ' de largeur sur  ' . $product_width . ' de hauteur.</div>';
	}
	if ( $product->has_dimensions() ) {
		echo '<div class="size_artdim">Dimensions : ' . $product_dimensions . '</div>';
	}
		
}
add_action( 'woocommerce_shop_loop_item_title', 'taille_woo_attribute', 10 );

Notez que $product_width et lenght peuvent être supprimé car non utilisés, mais il pourrait servir à retourner juste d'autres valeurs dans le "echo". Voir sur le lien suivant les valeurs récupérables sur un produit.

Liens des informations produits : https://www.businessbloomer.com/woocommerce-easily-get-product-info-title-sku-desc-product-object/

Dans un code bloc vous pouvez très bien récupérer le template par défaut de WooCommerc avec

<?php
global $product;

/**
 * Hook: woocommerce_before_single_product.
 *
 * @hooked woocommerce_output_all_notices - 10
 */
do_action( 'woocommerce_before_single_product' );

if ( post_password_required() ) {
	echo get_the_password_form(); // WPCS: XSS ok.
	return;
}
?>
<div id="product-<?php the_ID(); ?>" <?php wc_product_class( '', $product ); ?>>

	<?php
	/**
	 * Hook: woocommerce_before_single_product_summary.
	 *
	 * @hooked woocommerce_show_product_sale_flash - 10
	 * @hooked woocommerce_show_product_images - 20
	 */
	do_action( 'woocommerce_before_single_product_summary' );
	?>

	<div class="summary entry-summary">
		<?php
		/**
		 * Hook: woocommerce_single_product_summary.
		 *
		 * @hooked woocommerce_template_single_title - 5
		 * @hooked woocommerce_template_single_rating - 10
		 * @hooked woocommerce_template_single_price - 10
		 * @hooked woocommerce_template_single_excerpt - 20
		 * @hooked woocommerce_template_single_add_to_cart - 30
		 * @hooked woocommerce_template_single_meta - 40
		 * @hooked woocommerce_template_single_sharing - 50
		 * @hooked WC_Structured_Data::generate_product_data() - 60
		 */
		do_action( 'woocommerce_single_product_summary' );
		?>
	</div>

	<?php
	/**
	 * Hook: woocommerce_after_single_product_summary.
	 *
	 * @hooked woocommerce_output_product_data_tabs - 10
	 * @hooked woocommerce_upsell_display - 15
	 * @hooked woocommerce_output_related_products - 20
	 */
	do_action( 'woocommerce_after_single_product_summary' );
	?>
</div>

<?php do_action( 'woocommerce_after_single_product' ); ?>

Dans le cas de problèmes avec le module "Product Image" qui serait insérer dans un repeater, vous pouvez utiliser

<?php
	do_action( 'woocommerce_before_single_product_summary' );
?>

Attention que l'avantage de cette action est de récupérer également les badges associés aux produits. Utiliser un fonctions plus sélective peut vous rendre un contenu plus précis mais pas forcément la totalité du code voulu.

Liens des références des hook : https://docs.woocommerce.com/wc-apidocs/hook-docs.html

Anime.js est une bibliothèque d'animation JavaScript légère avec une API simple mais puissante facilement utilisable avec Oxygen.
Il fonctionne avec les propriétés CSS, SVG, les attributs DOM et les objets JavaScript.

Il suffira pour ces exemples de rajouter un bloc de code dans votre page Oxygen avec par exemple (exemple 7 du dernier lien an-dessous) :

<h1 class="ml7">
  <span class="text-wrapper">
    <span class="letters">Reality is broken</span>
  </span>
</h1>

Dans le css

.ml7 {
  position: relative;
  font-weight: 900;
  font-size: 3.7em;
}
.ml7 .text-wrapper {
  position: relative;
  display: inline-block;
  padding-top: 0.2em;
  padding-right: 0.05em;
  padding-bottom: 0.1em;
  overflow: hidden;
}
.ml7 .letter {
  transform-origin: 0 100%;
  display: inline-block;
  line-height: 1em;
}

Et dans le javascript :

// Wrap every letter in a span
var textWrapper = document.querySelector('.ml7 .letters');
textWrapper.innerHTML = textWrapper.textContent.replace(/\S/g, "<span class='letter'>$&</span>");

anime.timeline({loop: true})
  .add({
    targets: '.ml7 .letter',
    translateY: ["1.1em", 0],
    translateX: ["0.55em", 0],
    translateZ: 0,
    rotateZ: [180, 0],
    duration: 750,
    easing: "easeOutExpo",
    delay: (el, i) => 50 * i
  }).add({
    targets: '.ml7',
    opacity: 0,
    duration: 1000,
    easing: "easeOutExpo",
    delay: 1000
  });

Démos sur ce site : https://oxygen.bulgaweb.com/moving-letters/

Lien du Javascript : https://animejs.com/

Lien des tutoriels "Moving Letters" : https://tobiasahlin.com/moving-letters/

Vous pouvez également utiliser mon plugin Oxychild qui inclut le javascript (à activer) DOWNLOAD

Isotope permet de filtrer les catégories avec le module Easypost (car il dispose d'un template que le repeater n'a pas). Globalement nous devrons insérer les slugs des catégories en classe pour chaque articles.

Afin de facilité la mise en place, vous pouvez utiliser mon plugin "OxyChild" qui dispose de la fonction nécessaire et des fichiers javascript. Il vous suffira d'activer le functions.php et l'insertion des javascript en activant Isotope.

Nous allons d'abord récupérer les catégories et en faire des boutons pour filtrer. Insérer un bloc de code au-dessus de votre module easypost. Il faudra donc utiliser cette fonction dans ce bloc et bien modifier "ma-taxonomie" par votre taxonomie personnelle (fonctionne avec les CPT)

oxychild_get_filters('ma-taxonomie');

Note : le nom de la fonction avec oxychild peut être changé. J'ai remplacé mon plugin maison OxyChild par Advanced Script. Je crée donc un script PHP que j'appelle Functions et il doit contenir ce code :

/* Functions needed for Isotope JS */

function oxychild_get_filters($taxonomy)
{
	$terms = get_terms($taxonomy);
	$count = count($terms);
	if ($count > 0) { ?>
		<div class="portfolio-categories filter-button-group">
			<button class="active" data-filter="*"><?php esc_html_e('TOUT', 'text-domain'); ?></button>
			<?php foreach ($terms as $term) { ?>
				<button data-filter=".<?php echo esc_attr($term->slug); ?>"><?php echo esc_html($term->name); ?></button>
			<?php } ?>
		</div>
		<?php
	}
}

Et ce css dans le même bloc que vous allez personnaliser à votre goût.

.filter-button-group button {
    margin-right: 10px;
    margin-bottom: 14px;
    padding: 10px 20px;
    border: none;
    border-radius: 15px;
    background-color: #1d3c2e;
    color: #fff;
    font-weight: normal;
    letter-spacing: normal;
    text-transform: uppercase;
    cursor: pointer;
    font-size: 13px;
}

.filter-button-group button:hover,
.filter-button-group button.active {
    color: #fff;
    background-color: #63917c;
}

.filter-button-group button:focus {
    outline-style: none;
    outline-color: transparent;
}
.filter-button-group {
	display: flex !important;
    flex-wrap: wrap;
    justify-content: center;
}

Ensuite nous allons nous rendre dans le template php d'easypost et remplacer la première ligne (div avec la classe oxy-post) avec celle-ci (remplacer également "ma-taxonomie")

<div class='oxy-post <?php 
            $categories = get_the_terms( $post->ID, 'ma-taxonomie' );
foreach( $categories as $category ) { 
  echo ' ' . $category->slug;
} 
?> '>

Si vous avez bien réaliser tous les instructions, vous devriez pouvoir filtrer vos postes.

Note : vous pouvez remplacer dans la fonction, située dans functions.php, le mot "TOUT" par ce qui vous conviens le mieux.

Lien d'Isotope : https://isotope.metafizzy.co/

La structure du code de base

Au tout début, la première chose dont nous aurons besoin est un bloc de code de départ que nous pouvons modifier selon nos besoins:

<?php
$params = array('posts_per_page' => 5); // (1)
$wc_query = new WP_Query($params); // (2)

if ($wc_query->have_posts()) : // (3) 
while ($wc_query->have_posts()) : // (4)
                $wc_query->the_post(); // (4.1) 
the_title(); // (4.2) 
endwhile;
wp_reset_postdata(); // (5)
else: ?>
<p>
     <?php _e( 'No Products' ); // (6) ?>
</p>
<?php endif; ?>

Le code ci-dessus extrait les titres des cinq articles les plus récents de notre base de données WordPress en utilisant le processus suivant:

  1. Un tableau de paramètres avec lequel WP_Query fonctionne est créé; pour commencer, ce ne sont que les publications de base, mais en ajoutant plus de détails à ces paramètres, nous pouvons obtenir des résultats différents pour nos requêtes.
  2. WP_Query est utilisé pour interroger les paramètres créés dans la première ligne.
  3. La requête est vérifiée pour voir si elle a renvoyé des résultats.
  4. S'il y a des résultats, nous les répétons:
    4.1 Tout d'abord, définissez la variable globale $ post, qui garantit le fonctionnement de la fonction suivante.
    4.2 Deuxièmement, définir la variable the_title (), qui est responsable de l'affichage du titre du message.
  5. Ensuite, lorsque les articles sont affichés, nous retournons la variable $ post à son état d'origine avec la fonction wp_reset_postdata.
  6. Dans le cas où la vérification à l'étape 3 constate qu'il n'y a pas de publications à afficher, au lieu d'itérer sur des résultats inexistants, nous affichons simplement une invite appropriée.

Tirer des produits WooCommerce au lieu de messages WordPress

Tout ce que nous devons faire est de changer le tableau des paramètres de requête pour inclure le paramètre post_type et lui dire de récupérer les produits :

$params = array(
        'posts_per_page' => 5, 
        'post_type' => 'product'
);

Affichage des produits WooCommerce en promotion

Dans WooCommerce, un champ sale_price est chargé de définir le prix spécial réduit; lorsque le produit n'est plus en promotion, ce champ est vide.

$params = array(
'posts_per_page' => 5, 
'post_type' => 'product',
'meta_key' => '_sale_price',
'meta_value' => '0',
'meta_compare' => '>='
);

Affichage de variantes de produits promotionnels

Le code de la dernière section s'occupe d'afficher les produits en promotion, mais qu'en est-il des variantes d'un seul produit? Après tout, si une variante est en vente, nous voudrons probablement aussi que le reste des variantes soit en vente! La raison pour laquelle le code de la dernière section n'affiche pas les variantes en standard est que WooCommerce stocke chaque variante de produit en tant que publication distincte et en tant que publication d'un autre type. Pour contourner ce problème, nous devons apporter une autre petite modification à notre tableau de paramètres:

$params = array(
'posts_per_page' => 5, 
'post_type' => array('product', 'product_variation'),
'meta_key' => '_sale_price',
'meta_value' => 0,
'meta_compare' => '>='
'meta_type' => 'NUMERIC'
);

Displaying available products only

Vos clients ne seront pas très satisfaits si vous essayez de leur vendre un produit sur votre page d'accueil que vous n'avez pas en stock, c'est donc une bonne idée d'inclure une telle vérification dans votre code. La situation de stockage est gérée par le champ _stock_status, qui prend deux valeurs: instock et outofstock. Ainsi, pour afficher les produits dont le prix est inférieur à 5 et qui sont en stock, nous devons utiliser les paramètres suivants :

$params = array(
        'posts_per_page' => 5, 
        'post_type' => array('product', 'product_variation'),
        'meta_query' => array(
            array(
                'key' => '_price',
                'value' => 5,
                'compare' => '<',
                'type' => 'NUMERIC'
            ),
            array(
                'key' => '_stock_status',
                'value' => 'instock'
            )
        )
);

Source : https://www.gavick.com/blog/wp_query-woocommerce-products

Autres informations en anlgais : https://github.com/woocommerce/woocommerce/wiki/wc_get_products-and-WC_Product_Query

Utiliser les queries dans WordPress vous permets de récupérer quasi ce que vous voulez sur vos pages. Voici une fonction qui vous permettra de récupérer les articles relatifs :

<?php 

$current_post = get_queried_object();

$args = array(
   'post_type' => 'mon-post-type',
   'posts_per_page' => 5,
   'post__not_in' => [$current_post->ID]
);

$query = new WP_Query($args);
	while($query->have_posts()) : $query->the_post();         
?>
<p><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></p>
<?php 
	endwhile; 
wp_reset_query();
?>

La fonction est à mettre dans un code bloc sur le template des posts en remplaçant mon-post-type par le slug de votre articles.

Note : 'post__not_in' => [$current_post->ID] ce code supprime de la liste l'article sur lequel l'utilisateur se trouve.

Suite de mon premier tutoriel (qui devenait long) pour l'ajout d'un panier sur un site WooCommerce (compatible avec WPML). Basé sur des propositions/aides d'utilisateurs du groupe Facebook anglais d'Oxygen.

Solution par plugin

La solution la plus simple est d'utiliser ce plugin https://wordpress.org/plugins/woocommerce-menu-bar-cart/ (ou un autre du genre). Pour rappel avec Oxygen, si vous voulez votre panier dans la barre de côté, il faudra utiliser WooSidebars.

Solution avec du code

Un utilisateur a expliqué qu'il est possible de récupérer la fonction du thème Storefront de WooCommerce et de l'intégrer dans notre site réalisé avec Oxygen. Voici son site en allemand https://wewiradirekt.de/ .

La première étape sera d'installer, si ce n'est déjà fait, Code Snippet pour mettre la fonction. https://wordpress.org/plugins/code-snippets/ et d'y insérer

<?php function wc_refresh_mini_cart_count($fragments){
ob_start();
?>
<div id="mini-cart-count">
<?php echo WC()->cart->get_cart_contents_count(); ?>
</div>
<?php
$fragments['#mini-cart-count'] = ob_get_clean();
return $fragments;
}
add_filter( 'woocommerce_add_to_cart_fragments', 'wc_refresh_mini_cart_count');

Ensuite nous allons aller placer notre panier dans le menu (mais cette version permet le placement là où vous le voulez) en allant dans le template Main (ou équivalent).

A l'endroit voulu dans votre menu :

1 Créer une div avec deux classes "custom-mini-cart" et "position-relative" (important pour la suite)

2 Placer votre icône représentant le panier

3 Mettre un module de bloc de code avec dans la partie PHP/HTML (Note : "Panier" est à traduire si le site n'est pas en français)

<a class="ct-link-button cart-button" href="/panier/" title="Panier">Panier</a>
<div id="mini-cart-count"></div>
<div id="mini-cart-wrapper">
  <div class="widget_shopping_cart_content"><?php woocommerce_mini_cart(); ?></div>
</div>

4 Mettre le CSS dans la feuille de style CSS (stylesheet) et le personnaliser à votre site.

/*-- CART --*/
#mini-cart-count {
    display: inline-block;
    color: white;
    background: #0000ff;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    padding-top: 4px;
    text-align: center;
    font-size: 12px;
    font-weight: 800;
    margin-left: 10px;
}
#mini-cart-wrapper {
    position: absolute;
    top: calc(100% + 1px);
    left: 50%;
    transform: translate(-50%,10%);
    background-color: #d3ced2;
    backdrop-filter: blur(20px) saturate(180%);
    border-radius: 4px;
    padding: 25px;
    color: white;
    pointer-events: none;
    opacity: 0;
    text-align: center;
    transition: all 50ms linear;
  z-index: 99;
}
.cart-button {
    background-color: transparent;
    border: 1px solid #0000ff; 
    color: #0000ff;
    padding: 7px 15px;
    font-weight: 600;
}
.position-relative {
    position: relative!important;
}
.widget_shopping_cart_content {
    width: 330px;
}
.custom-mini-cart:hover #mini-cart-wrapper {
    pointer-events: all;
    opacity: 1;
    transform: translate(-50%,0%);
    transition: all 240ms linear;
}
.cart-button.ct-link-button {
    color: #0000ff;
    padding: 2px 16px;
}
#mini-cart-wrapper a:not(.remove) {
    display: inline-flex;
    flex-direction: row;
    flex-wrap: nowrap;
    width: 90%;
    text-align: left;
    align-items: center;
}
.custom-mini-cart .woocommerce-mini-cart.cart_list.product_list_widget {
    margin: 0px;
}
.buttons.woocommerce-mini-cart__buttons {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: center;
}
.custom-mini-cart .mini_cart_item, .woocommerce .custom-mini-cart ul.product_list_widget li {
    display: flex;
    flex-wrap: wrap;
    margin-bottom: 8px;
    background-color: rgba(255,255,255,0.04);
    padding-top: 10px;
    border: none;
}
.woocommerce ul.product_list_widget li {
    border-bottom: 1px solid #d3ced2;
    margin-bottom: 4px;
    padding-bottom: 8px;
}
.widget_shopping_cart_content .woocommerce-mini-cart__total {
    margin-bottom: 0px!important;
    text-align: left;
}

REMARQUE : le contenu du panier est visible lors du survol du bouton. J'avais essayé de descendre le contenu du panier mais dans ce cas le passage du survol du bouton au contenu du panier fait que le "wrapper" se ferme. Pour la personnalisation vous devez avoir les notions nécessaires du code CSS.

Préambule :

Je ne suis pas développeur et je partage mon expérience. La demande de mon client (en sous-traitance) était d’avoir un site e-commerce qui soit mis à jour quotidiennement depuis la caisse enregistreuse d’un magasin. Le développeur envoie un fichier xml en FTP qui est lancé par une commande cron tous les soirs (jours ouvrables du magasin) avec WP All Import (plugin également de Soflyy). Vu la lenteur du site avec mon ancien thème, j’ai refait le site avec Oxygen et j’ai supprimé certains plugins (Ultimate Member notamment) et simplifié pour conserver de bonnes performances. Le client m’a donné les instructions du design qui est très simple (le client est Roi).

WPML avec Oxygen

J’utilise la duplication de mes templates et pages après avoir réalisé mon site dans la première langue. Pour réaliser cette opération il faudra autoriser WPML à dupliquer les templates d’Oxygen (les pages et articles sont normalement configurés directement). Il faudra se rendre dans “WPML > Paramètres > Traduction des types de publication” et activer “Templates”
Note : ceci doit être également réalisé si vous travaillez avec des blocks à traduire ou d’autres éléments. Pour les Widgets, mettre le plugin WooSidebars et là je crée mes widgets pour les deux langues.

Ensuite, se rendre dans “WPML > Gestion des traductions” et sélectionner le contenu à traduire. Dans l’image ci-dessous j’ai rajouté uniquement une page Test pour l’exemple. Dans votre cas il faudra choisir toutes les pages voulues et ensuite répéter l’opération pour tous les templates. Cochez “Dupliquer le contenu” et ensuite validez avec “Duplication”.

À partir de là, vous pouvez vous rendre dans vos pages et templates et, en choisissant la seconde langue, vous avez toutes vos pages dupliquées mais identiques à la première langue. Il nous reste juste une opération à réaliser sur CHAQUE page/template de la seconde (ou plus) langue. En se rendant sur la page, il faut demander à WPML de traduire la "copie" à part de manière à garder deux différentes, ce qui est le but. Donc, cliquez sur "Traduire à part" et ensuite vous pouvez traduire/changer le contenu de la page/template dans l’autre langue.

Note : prendre en compte le fait qu’à intérieur des templates il faudra modifier certains paramètres pour les queries ainsi que les widgets insérés. C’est logique. Ne pas oublier qu’il faut, suivant les cas, traduire les attributs et catégories mais ce tutoriel est juste fait pour aider l’intégration avec Oxygen.

Pages de connexion / déconnexion WooCommerce

Certains doivent le savoir mais pour moi ce fut une petite surprise. Réaliser une page de connexion avec WooCommerce est très simple. Par défaut lorsque vois insérer le module "My account" d’Oxygen et que le client n’est pas connecté vous avez un bloc avec deux colonnes S’enregistrer et Se connecter. Personnellement je voulais avoir mes formulaires Se connecter et S’inscrire séparés. Un peu de CSS est suffisant.
Note : le module "My account" dans l’édition d’Oxygen ne montre pas le même résultat que sur le front-end (site), pas de panique. Le code block contient le CSS pour séparer les deux colonnes.

CSS pour conserver uniquement la colonne connexion (peut varier suivant votre personnalisation, c’est une base) :

.woocommerce .col2-set .col-2, .woocommerce-page .col2-set .col-2 {
     display: none;
 }
 .woocommerce .col2-set .col-1, .woocommerce-page .col2-set .col-1 {
     float: left;
     width: 100%;
 }

Pour une page S’inscrire :

.woocommerce .col2-set .col-1, .woocommerce-page .col2-set .col-1 {
     display: none;
 }
 .woocommerce .col2-set .col-2, .woocommerce-page .col2-set .col-2 {
     float: right;
     width: 100%;
 }

Et voilà ???? (le cadre peut être enlevé à votre convenance)

Dernier point, l’accès pour la connexion

Oxygen permet avec les conditions l’accès aux pages selon que l’utilisateur est connecté ou pas (User logged in) mais je voulais dans mon menu que le client voit Se connecter s’il n’est pas connecté et Déconnexion s’il est connecté. Dans ce cas il faudra installer User menu (gratuit) qui va résoudre ce point. Après installation, rendez-vous dans votre menu et choisissez les pages à autoriser (dans mon cas Connexion/Déconnexion ainsi que Mon Compte) et changer les conditions. WooCommerce, dans la section menu, propose les Terminaisons WooCommerce (à activer éventuellement dans les options de l’écran) où vous trouverez la Déconnexion et où vous pourrez choisir la redirection après déconnexion.

Lien de User Menus https://fr.wordpress.org/plugins/user-menus/

Voilà, pour ce tutoriel, j’espère qu’il vous a été utile et qu’il est clair. Bon travail et, comme on dit, "Y a plus qu’à ... "

Pour un projet je voulais changer la couleur de fond d'un champ (badge) provenant d'un champs Pods (ou ACF) en fonction du texte de son contenu (liste).

Il faut donc ajouter une classe à votre champ dynamique (dans ce cas mts-badge) et ciblé le mot voulu. Et ensuite utilisé ce code jQuery :

jQuery( "div.mts-badge:contains('Sold')").each(function() {
  jQuery(this).css( "background-color", "red");});

Merci à Lucas Chaplain pour son aide ...

Copyright © 2019 - 2023 Bulgaweb
 | 
Développé par BulgaWeb
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram