Wordpress Jenkler theme



  • Jenkler namnkonvention

    Länk: wordpress-theme-jenkler

    Språk: Vi använder 2 tecken som visar vilket språk det är (*en, sv, gb). Dock så skrivs standardspråket aldrig ut i namnet. Om sidan är engelsk så struntar vi i en och är den svensk så strunta vi i sv.

    Sidor

    Denna meny är synlig för användare med minst editor rättighet (capability: edit_pages).

    För texter som ska kunna ändras av kunden (editor rättighet) används anpassade fält om det är kortare texter, annars Shortcode Text shortcodes (se nedan). Namnstandarden för anpassade fält är text-<sektion>

    [field]text-namn[/field]

    Shortcoden field som används för att visa anpassade fält, skrivs vanligtvis i en Shortcode Code eller Shortcode Text. Fungerar ej i Inlägg.

    Det finns även några några reserverade anpassade fält, se följande lista

    seo-description (meta description för sidan)
    seo-keywords (meta keyword för sidan)
    seo-title (title taggen för sidan)

    Sidor / Global

    Denna meny är synlig för användare med admin rättighet (capability: manage_options). Har stöd för PHP-kod.

    Symbolen # betyder att namnen är reserverat och att koden körs från backend-mallar.

    #404 (När en sida inte finns)
    #archive (kategori- och tag-sidor)
    #archive-product (woocommerce produktarkiv)
    #content-product (woocommerce produktarkiv en produkt)
    #content-single-product (woocommerce produktsida produktbeskrivning)
    #footer (html-fot) *
    #header (html-head) *
    #home (arkivsida för blogginlägg)
    #index (standardmall för sidor)
    #page-custom-01 (custom-mall 1 för sidor)
    #page-custom-02 (custom-mall 2 för sidor)
    #search (sökresultat för wordpress)
    #single (standardmall för ett Inlägg)
    #single-product (woocommerce produktsida)

    * Obligatorisk.

    Allt annat under global körs alltid. Det är bra att välja namn med omsorg. Använd !is_admin() för att inte köra vissa saker i wordpress admin. Följande namn används oftast.

    functions (blandade små funktioner)
    mail (hanterar formulär-POST-data)
    navwalker (walker för menysystem)
    woocommerce (woocommerce specifik kod)

    Om man ska använda shortcodes så måste man skriva php koden för att hämta data. Exempel:

    j_get('j-shortcode-code', 'permalänk');
    j_get('j-shortcode-code', 'permalänk', array('name' => 'joe'));
    j_get('j-shortcode-text', 'permalänk', array('name' => 'joe'));

    Sidor / Shortcode Code

    Denna meny är synlig för användare med admin rättighet (capability: manage_options). Har stöd för PHP-kod.

    Symbolen # betyder att shortcoden inte hör till en specifik sida utan är en kodsnutt som kan läggas in på ett eller flera ställen.

    #bottom (sidfot primärspråk)
    #bottom-en (sidfot engelska)
    #breadcrumb (länkstig primärspråk)
    #breadcrumb-en (länkstig engelska)
    #menu (huvudmeny primärspråk)
    #menu-<name> (Där <name> är ett beskrivande namn på menyn)
    #menu-en (huvudmeny engelska)
    #menu-en-<name> (Där <name> är ett beskrivande namn på menyn)
    #top (sidhuvud primärspråk)
    #top-en (sidhuvud engelska)

    Sidor

    Använd ordet page plus hela permalänken som den ser ut i frontend som namn. Se exempel nedan.

    page (/) (startsida primärspråk)
    page-en (/en/) (startsida engelska)
    page-om-oss (/om-oss/)
    page-en-about-us (/en/about-us/)
    page-en-om-oss-foretaget (/en/om-oss/foretaget/)
    page-en-om-oss-kontakt (/en/om-oss/kontakt/)

    Shortcoden läggs in genom att skriva följande:

    [code]permalänk[/code]
    [code name="joe"]permalänk[/code] (För att använda attribut. Skriv %name% för att visa attributet)

    Här fungerar shortcodes i shortcodes.

    Sidor / Shortcode Text

    Denna meny är synlig för användare med minst editor rättighet (capability: edit_pages).

    Används för längre texter som kunden ska kunna ändra själv.

    Shortcoden läggs in genom att skriva följande:

    [text]permalänk[/text]
    [text name="joe"]permalänk[/text] (För att använda attribut. Skriv %name% för att visa attributet)

    Här fungerar shortcodes i shortcodes.



  • Webassets

    Sajtspecifika assets såsom media, scripts och css lägger man upp med mediabiblioteket i Wordpress. Det går även bra att länka in kod från webben via kända CDN-källor om man vill det. Alla assets länkas in från global -> functions. Se functions-mallen för exempel.

    Under utveckling så stänger vi av:

    • Inställningar -> Media
      Organisera mina uppladdade filer i kataloger enligt månad och år

    Detta för att alla bilder, script och css skall hamna under i rooten på upload. När sedan kunden skall skriva inlägg så ska denna vara aktiv så att bilderna laddas upp i rätt struktur <år><månad>.

    Observera att även filer i mediebiblioteket får en permalänk som kan krocka med sidor. Därför är det bra att ändra permalänken till hela filnamnet och byta ut . mot -.

    Exempel på det som skall laddas upp i mediabibliotektet

    Målet är att ladda upp så mycket assets som behövs som möjligt för att minska laddningstider. Dock så är vissa mycket knepiga att ladda in som man bör köra via CDN istället. Bootstrap hittar du på https://getbootstrap.com.

    • bootstrap.min.css (ladda bara upp denna ifall du inte kör bootstrap css i custom.css genererat med sass)
    • bootstrap.min.js
    • custom.css
    • custom.scss
    • popper.min.js

    När det gäller custom.css filen så kan man använda node-sass för att generera den. Den filen läggs sedan in under uploads/ via mediabiblioteket. I functions mallen ser man hur detta länkas in.

    Exempel på CDN källor

    • Font Awesome - För ikoner på siten. Använd SVG & JS. Vid användning av unicode-tecken, använd woff font-face filer.
    wp_enqueue_script('fontawesome', 'https://use.fontawesome.com/releases/v5.2.0/js/all.js');
    
    
    • Google Fonts - Använd embed och custumize för att ställa in rätt kod på siten.
    wp_enqueue_style('font-lato', 'https://fonts.googleapis.com/css?family=Lato:300,300i,400,700');
    
    




  • Kodningsstandard

    • Använd 2 space istället för tab
    • Sätt inte startbracket på ny rad
    • Använd samma namnstruktur som gruntprojektet har (camelCase i Nodejs, underscore_case i Wordpress)


  • Mallar

    Defaultmallar som kan vara bra att använda om det skulle försvinna från dev

    Global

    #404

    <?php
    get_header();
    echo j_get('j-shortcode-code', 'top');
    ?>
    <div>404</div>
    <?php
    echo j_get('j-shortcode-code', 'bottom');
    get_footer();
    ?>
    

    #archive

    <?php
    get_header();
    echo j_get('j-shortcode-code', 'top');
    ?>
    <div>Archive</div>
    <?php
    echo j_get('j-shortcode-code', 'bottom');
    get_footer();
    ?>
    

    #footer

    
    

    #header

    <?php
    $charset = get_option('blog_charset');
    if($charset == '') $charset = 'UTF-8';
    $title = trim(wp_title('', false));
    if($title == '') $title = get_option('blogname').' '.get_option('blogdescription');
    $seo_description = j_custom_field('', 'seo-description');
    $seo_keywords = j_custom_field('', 'seo-keywords');
    $seo_title = j_custom_field('', 'seo-title');
    $title = $seo_title ? $seo_title : $title;
    ?>
    <meta charset="<?php echo $charset?>"/>
    <meta content="Jenkler IT AB" name="author"/>
    <?php if($seo_description) echo '<meta content="'.$seo_description.'" name="description"/>'."\n"?>
    <?php if($seo_keywords) echo '<meta content="'.$seo_keywords.'" name="keywords"/>'."\n"?>
    <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport"/>
    <title><?php echo $title?></title>
    

    #home

    <?php
    get_header();
    echo j_get('j-shortcode-code', 'top');
    ?>
    <div>Home</div>
    <?php
    echo j_get('j-shortcode-code', 'bottom');
    get_footer();
    ?>
    

    #index

    <?php
    remove_filter('the_content', 'wpautop');
    remove_filter('the_excerpt', 'wpautop');
    
    get_header();
    if(have_posts()) {
      while(have_posts()) {
        the_post();
        the_content();
      }
    }
    get_footer();
    ?>
    

    #search

    <?php
    get_header();
    echo j_get('j-shortcode-code', 'top');
    ?>
    <div>Search</div>
    <?php
    echo j_get('j-shortcode-code', 'bottom');
    get_footer();
    ?>
    

    #single

    <?php
    get_header();
    echo j_get('j-shortcode-code', 'top');
    ?>
    <div>Single</div>
    <?php
    echo j_get('j-shortcode-code', 'bottom');
    get_footer();
    ?>
    

    functions

    <?php
    function j_enqueue() {
      wp_enqueue_script('jquery');
      wp_enqueue_script('popper', '/wp-content/uploads/popper.js');
      wp_enqueue_script('bootstrap', '/wp-content/uploads/bootstrap.js');
      wp_enqueue_style('custom', '/wp-content/uploads/sdilab.css');
    }
    add_action('wp_enqueue_scripts', 'j_enqueue');
    ?>
    

    mail

    <?php
    function j_mail() {
      $message = strip_tags(trim($_POST["message"]));
      if(strstr($message, '://')) {
        wp_die('', 200);
        return;
      }
      $email = filter_var(trim($_POST["email"]), FILTER_SANITIZE_EMAIL);
      $name = strip_tags(trim($_POST["name"]));
      $phone = strip_tags($_POST['phone']);
    
      if(!filter_var($email, FILTER_VALIDATE_EMAIL) || empty($message) || empty($name) || empty($phone)) {
        wp_die('', 400);
        return;
      }
    
      $body = "Name: $name<br>";
      $body .= "Number: $phone<br>";
      $body .= "Email: $email<br>";
      $body .= "Message: $message<br>";
    
      $to = '[email protected]';
      $subject = "Form: dev.jenkler.com - $email";
      $headers[] = "Content-Type: text/html; charset=UTF-8";
      $headers[] = "Reply-To: $name <$email>";
    
      if(wp_mail($to, $subject, $body, $headers)) wp_die('', 200);
      else wp_die('', 400);
    }
    add_action('admin_post_mail', 'j_mail');
    add_action('admin_post_nopriv_mail', 'j_mail');
    ?>
    

    sitemap

    <?php
    if(!is_admin()) {
      if(j_is_path() == 'sitemap.xml/') {
        header('Content-type: text/xml');
        $sitemap = '<?xml version="1.0" encoding="UTF-8"?>';
        $sitemap .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
        $args = array(
          'post_status' => 'publish',
          'post_type' => array('page', 'post'),
          'posts_per_page' => -1
        );
        $items = get_posts($args);
        if(is_array($items)) foreach($items as $item) {
          $sitemap .= '<url>';
          $sitemap .= '<loc>'.get_permalink($item->ID).'</loc>';
          $sitemap .= '<lastmod>'.date('Y-m-d', strtotime($item->post_modified)).'</lastmod>';
          $sitemap .= '<changefreq>weekly</changefreq>';
          $sitemap .= '<priority>0.8</priority>';
          $sitemap .= '</url>';
        }
        echo $sitemap.'</urlset>';    
        exit(); 
      }
    }
    ?>
    

    woocommerce

    <?php
    function woocommerce() {
      add_theme_support('woocommerce');
    }
    add_action('after_setup_theme', 'woocommerce');
    ?>
    

    Shortcode Code

    Mail front-end kodexempel

    <h2>Kontakta oss gärna genom att fylla i uppgifterna</h2>
    
    <form action="/wp-admin/admin-post.php" id="ajax-contact" method="post">
    <input type="hidden" name="action" value="mail">
    <div class="form-group">
    <label for="name">Namn</label>
    <input type="name" name="name" class="form-control" id="name" placeholder="Vad är ditt namn?" required="">
    </div>
    <div class="form-group">
    <label for="phone">Nummer</label>
    <input type="name" name="phone" class="form-control" id="phone" placeholder="Vilket telefonnummer kan vi nå dig på?" required="">
    </div>
    <div class="form-group">
    <label for="email">Email</label>
    <input type="email" name="email" class="form-control" id="email" placeholder="Vad har du för e-postadress?" required="">
    </div>
    <div class="form-group">
    <label>Meddelande</label>
    <textarea class="form-control" name="message" placeholder="Beskriv kort vad behöver du hjälp med? Notera att meddelanden som innehåller länkar kommer automatiskt att raderas." rows="3" required=""></textarea>
    </div>
    <input type="submit" class="btn btn-primary" value="Skicka">
    </form>
    <br>
    <h4>
    <div id="form-error" style="display: none;">
    Någonting gick fel, maila gärna manuellt till adressen i foten på sidan.
    </div>
    <div id="form-ok" style="display: none;">
    Tack för ditt meddelande! Jag återkommer så snart jag kan.
    </div>
    </h4>
    
    <script>
        var form = jQuery('#ajax-contact');
        var formMessages = jQuery('#form-messages');
    
        jQuery(form).submit(function(event)
        {
            event.preventDefault();
            var formData = jQuery(form).serialize();
            jQuery.ajax({
                type: 'POST',
                url: jQuery(form).attr('action'),
                data: formData
            }).done(function(response) {
               jQuery("#form-error").hide();           
               jQuery("#form-ok").show();
                jQuery(form).remove();            
            }).fail(function(data) {
               jQuery("#form-error").show();
               jQuery("#form-ok").hide();
            });
        });
    </script>
    


  • navwalker

    <?php
    // https://github.com/wp-bootstrap/wp-bootstrap-navwalker (2018-04-21)
    class j_navwalker extends Walker_Nav_Menu {
      public function start_lvl( &$output, $depth = 0, $args = array() ) {
        if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
          $t = '';
          $n = '';
        } else {
          $t = "\t";
          $n = "\n";
        }
        $indent = str_repeat( $t, $depth );
        $classes = array( 'dropdown-menu' );
        $class_names = join( ' ', apply_filters( 'nav_menu_submenu_css_class', $classes, $args, $depth ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
        $labelledby = '';
        preg_match_all( '/(<a.*?id=\"|\')(.*?)\"|\'.*?>/im', $output, $matches );
        if ( end( $matches[2] ) ) {
          $labelledby = 'aria-labelledby="' . end( $matches[2] ) . '"';
        }
        $output .= "{$n}{$indent}<ul$class_names $labelledby role=\"menu\">{$n}";
      }
    
      public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
          $t = '';
          $n = '';
        } else {
          $t = "\t";
          $n = "\n";
        }
        $indent = ( $depth ) ? str_repeat( $t, $depth ) : '';
    
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    
        $linkmod_classes = array();
        $icon_classes    = array();
    
        $classes = self::seporate_linkmods_and_icons_from_classes( $classes, $linkmod_classes, $icon_classes, $depth );
    
        $icon_class_string = join( ' ', $icon_classes );
    
        $args = apply_filters( 'nav_menu_item_args', $args, $item, $depth );
    
        if ( isset( $args->has_children ) && $args->has_children ) {
          $classes[] = 'dropdown';
        }
        if ( in_array( 'current-menu-item', $classes, true ) || in_array( 'current-menu-parent', $classes, true ) ) {
          $classes[] = 'active';
        }
    
        $classes[] = 'menu-item-' . $item->ID;
        $classes[] = 'nav-item';
    
        $classes = apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth );
    
        $class_names = join( ' ', $classes );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
    
        $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
    
        $output .= $indent . '<li itemscope="itemscope" itemtype="https://www.schema.org/SiteNavigationElement"' . $id . $class_names . '>';
        
        $atts = array();
    
        if ( empty( $item->attr_title ) ) {
          $atts['title'] = ! empty( $item->title ) ? strip_tags( $item->title ) : '';
        } else {
          $atts['title'] = $item->attr_title;
        }
    
        $atts['target'] = ! empty( $item->target ) ? $item->target : '';
        $atts['rel']    = ! empty( $item->xfn ) ? $item->xfn : '';
        $atts['href'] = ! empty( $item->url ) ? $item->url : '#';
        if($depth > 0) {
          $atts['class'] = 'dropdown-item';
        } else {
          $atts['class'] = 'nav-link';
        }
        $atts = self::update_atts_for_linkmod_type( $atts, $linkmod_classes );
        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
    
        $attributes = '';
        foreach ( $atts as $attr => $value ) {
          if ( ! empty( $value ) ) {
            $value       = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
            $attributes .= ' ' . $attr . '="' . $value . '"';
          }
        }
    
        $linkmod_type = self::get_linkmod_type( $linkmod_classes );
    
        $item_output = isset( $args->before ) ? $args->before : '';
        if ( '' !== $linkmod_type ) {
          $item_output .= self::linkmod_element_open( $linkmod_type, $attributes );
        } else {
          $item_output .= '<a' . $attributes . '>';
        }
    
        $icon_html = '';
        if ( ! empty( $icon_class_string ) ) {
          $icon_html = '<i class="' . esc_attr( $icon_class_string ) . '" aria-hidden="true"></i> ';
        }
    
        $title = apply_filters( 'the_title', $item->title, $item->ID );
        $title = apply_filters( 'nav_menu_item_title', $title, $item, $args, $depth );
    
        if ( in_array( 'sr-only', $linkmod_classes, true ) ) {
          $title         = self::wrap_for_screen_reader( $title );
          $keys_to_unset = array_keys( $linkmod_classes, 'sr-only' );
          foreach ( $keys_to_unset as $k ) {
            unset( $linkmod_classes[ $k ] );
          }
        }
    
        $item_output .= isset( $args->link_before ) ? $args->link_before . $icon_html . $title . $args->link_after : '';
        if ( '' !== $linkmod_type ) {
          $item_output .= self::linkmod_element_close( $linkmod_type, $attributes );
        } else {
          if(isset($args->has_children) && $args->has_children && 0 === $depth && $args->depth > 1) {
            $item_output .= '</a> <a href="#" aria-expanded="false" aria-haspopup="true" class="dropdown-toggle nav-link" data-toggle="dropdown"></a>';
          } else {
            $item_output .= '</a>';
          }
        }
    
        $item_output .= isset( $args->after ) ? $args->after : '';
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
      }
    
      public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
        if ( ! $element ) {
          return; }
        $id_field = $this->db_fields['id'];
        if ( is_object( $args[0] ) ) {
          $args[0]->has_children = ! empty( $children_elements[ $element->$id_field ] ); }
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
      }
    
      private function seporate_linkmods_and_icons_from_classes( $classes, &$linkmod_classes, &$icon_classes, $depth ) {
        foreach ( $classes as $key => $class ) {
          if ( preg_match( '/^disabled|^sr-only/i', $class ) ) {
            $linkmod_classes[] = $class;
            unset( $classes[ $key ] );
          } elseif ( preg_match( '/^dropdown-header|^dropdown-divider|^dropdown-item-text/i', $class ) && $depth > 0 ) {
            $linkmod_classes[] = $class;
            unset( $classes[ $key ] );
          } elseif ( preg_match( '/^fa-(\S*)?|^fa(s|r|l|b)?(\s?)?$/i', $class ) ) {
            $icon_classes[] = $class;
            unset( $classes[ $key ] );
          } elseif ( preg_match( '/^glyphicon-(\S*)?|^glyphicon(\s?)$/i', $class ) ) {
            $icon_classes[] = $class;
            unset( $classes[ $key ] );
          }
        }
        return $classes;
      }
    
      private function get_linkmod_type( $linkmod_classes = array() ) {
        $linkmod_type = '';
        if ( ! empty( $linkmod_classes ) ) {
          foreach ( $linkmod_classes as $link_class ) {
            if ( ! empty( $link_class ) ) {
    
              if ( 'dropdown-header' === $link_class ) {
                $linkmod_type = 'dropdown-header';
              } elseif ( 'dropdown-divider' === $link_class ) {
                $linkmod_type = 'dropdown-divider';
              } elseif ( 'dropdown-item-text' === $link_class ) {
                $linkmod_type = 'dropdown-item-text';
              }
            }
          }
        }
        return $linkmod_type;
      }
    
      private function update_atts_for_linkmod_type( $atts = array(), $linkmod_classes = array() ) {
        if ( ! empty( $linkmod_classes ) ) {
          foreach ( $linkmod_classes as $link_class ) {
            if ( ! empty( $link_class ) ) {
              if ( 'sr-only' !== $link_class ) {
                $atts['class'] .= ' ' . esc_attr( $link_class );
              }
              if ( 'disabled' === $link_class ) {
                $atts['href'] = '#';
                unset( $atts['target'] );
              } elseif ( 'dropdown-header' === $link_class || 'dropdown-divider' === $link_class || 'dropdown-item-text' === $link_class ) {
                unset( $atts['href'] );
                unset( $atts['target'] );
              }
            }
          }
        }
        return $atts;
      }
    
      private function wrap_for_screen_reader( $text = '' ) {
        if ( $text ) {
          $text = '<span class="sr-only">' . $text . '</span>';
        }
        return $text;
      }
    
      private function linkmod_element_open( $linkmod_type, $attributes = '' ) {
        $output = '';
        if ( 'dropdown-item-text' === $linkmod_type ) {
          $output .= '<span class="dropdown-item-text"' . $attributes . '>';
        } elseif ( 'dropdown-header' === $linkmod_type ) {
          $output .= '<span class="dropdown-header h6"' . $attributes . '>';
        } elseif ( 'dropdown-divider' === $linkmod_type ) {
          $output .= '<div class="dropdown-divider"' . $attributes . '>';
        }
        return $output;
      }
    
      private function linkmod_element_close( $linkmod_type ) {
        $output = '';
        if ( 'dropdown-header' === $linkmod_type || 'dropdown-item-text' === $linkmod_type ) {
          $output .= '</span>';
        } elseif ( 'dropdown-divider' === $linkmod_type ) {
          $output .= '</div>';
        }
        return $output;
      }
    }
    ?>
    

Log in to reply
 

Jenkler IT AB org.nr: 559082-6938   073-731 76 64   [email protected]