Przykład użycia funkcji GROUP_CONCAT

SELECT GROUP_CONCAT(kto ORDER BY kto ASC SEPARATOR ', ') FROM raport_ludzie_spotkania

Złączenie rekordów wątku do jednego stringa, wycinanie 80 znaków stringa:

SELECT t.ticket_id, t.created,
SUBSTRING(last_notes_title, 1, (80 + LOCATE(' ', last_notes_title, 80))) AS last_notes_title,
SUBSTRING(last_notes_body, 1, (80 + LOCATE(' ', last_notes_body, 80))) AS last_notes_body
FROM (
SELECT ticket_id, created,
GROUP_CONCAT(title ORDER BY created DESC SEPARATOR '|') AS last_notes_title,
GROUP_CONCAT(body ORDER BY created DESC SEPARATOR '|') AS last_notes_body
FROM ost_ticket_thread WHERE ticket_id IN (1,2,3,4,5) GROUP BY ticket_id
) AS t

Formatowanie daty w mysql

SELECT e.name,
DATE_FORMAT(FROM_UNIXTIME(start_time), '%Y-%d-%m') AS start_date_format,
DATE_FORMAT(FROM_UNIXTIME(start_time), '%H:%i:%S') AS start_time_format,
DATE_FORMAT(FROM_UNIXTIME(end_time), '%H:%i:%S') AS end_time_format,
TIMESTAMPDIFF(MINUTE, FROM_UNIXTIME(start_time),  FROM_UNIXTIME(end_time))
AS diff_time_minutes_format,
e.room_name,
e.start_time,
e.end_time,
WHERE e.room_id = r.id
 AND DATE_FORMAT(FROM_UNIXTIME(e.start_time), '%Y-%m-%d') <= '2016-05-23'
 AND DATE_FORMAT(FROM_UNIXTIME(e.end_time), '%Y-%m-%d') >= '2016-05-19'
 AND e.name IN ('misiek')
ORDER BY
 e.start_time

Jak przyspieszyć WordPress

Poniżej kilka trików które pozwoliły mi przyspieszyć bloga z 32/22 w PageSpeed Insigth do 90/100 – oczywiście to zależy od strony, ilości zdjęć, szybkości serwera itp, wszystko ma znaczenie.
I to jest blog ze zdjęciami (blog.grzegorztomicki.pl), jak dla mnie bardzo zacnie 🙂

1. Będziemy potrzebować dostęp do .htaccess
W którym dodajemy (nie będę opisywał co dokładnie jest w nim robione bo wszystko można znaleźć opisane w internecie)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
#</IfModule>



<IfModule mod_deflate.c>
  # Compress HTML, CSS, JavaScript, Text, XML and fonts
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml

  # Remove browser bugs (only needed for really old browsers)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  Header append Vary User-Agent
</IfModule>

<IfModule mod_expires.c>
  ExpiresActive on

# Perhaps better to whitelist expires rules? Perhaps.
  ExpiresDefault                          "access plus 1 month"

# cache.appcache needs re-requests in FF 3.6 (thx Remy ~Introducing HTML5)
  ExpiresByType text/cache-manifest       "access plus 0 seconds"



# Your document html
  ExpiresByType text/html                 "access plus 0 seconds"

# Data
  ExpiresByType text/xml                  "access plus 0 seconds"
  ExpiresByType application/xml           "access plus 0 seconds"
  ExpiresByType application/json          "access plus 0 seconds"

# RSS feed
  ExpiresByType application/rss+xml       "access plus 1 hour"

# Favicon (cannot be renamed)
  ExpiresByType image/x-icon              "access plus 1 week"

# Media: images, video, audio
  ExpiresByType image/gif                 "access plus 1 month"
  ExpiresByType image/png                 "access plus 1 month"
  ExpiresByType image/jpg                 "access plus 1 month"
  ExpiresByType image/jpeg                "access plus 1 month"
  ExpiresByType video/ogg                 "access plus 1 month"
  ExpiresByType audio/ogg                 "access plus 1 month"
  ExpiresByType video/mp4                 "access plus 1 month"
  ExpiresByType video/webm                "access plus 1 month"

# HTC files  (css3pie)
  ExpiresByType text/x-component          "access plus 1 month"

# Webfonts
  ExpiresByType font/truetype             "access plus 1 month"
  ExpiresByType font/opentype             "access plus 1 month"
  ExpiresByType application/x-font-woff   "access plus 1 month"
  ExpiresByType image/svg+xml             "access plus 1 month"
  ExpiresByType application/vnd.ms-fontobject "access plus 1 month"

# CSS and JavaScript
  ExpiresByType text/css                  "access plus 1 year"
  ExpiresByType application/javascript    "access plus 1 year"
  ExpiresByType text/javascript           "access plus 1 year"

  <IfModule mod_headers.c>
    Header append Cache-Control "public"
    Header unset ETag
    FileETag None
  </IfModule>

</IfModule>

2. Instalujemy „BJ Lazy Load”
Jest to plugin do „wolnego” ładowania się obrazków więcej na https://wordpress.org/plugins/bj-lazy-load/

3. Instalujemy „WP Super Cache”
Włączamy w nim w zakładce „Easy” na Caching on (Recommended) – więcej na https://wordpress.org/plugins/wp-super-cache/, czy działa można sprawdzić na stronie na samym dole powinien pojawić się mniej więcej taki wpis.

<!--HTML compressed, size saved 9.28%. From 64384 bytes, now 58410 bytes-->
<!-- Dynamic page generated in 0.974 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2016-01-01 11:42:46 -->


4. Najtrudniejsza część instalujemy „Above The Fold Optimization”

Nie włączamy go.
Klikamy na zakładkę „Extract Full CSS” pojawia się lista wszystkich css które są na stronie oraz textarea z połączonymi wszystkimi plikami css „Full CSS” – textarea.

Kopiuję Ctrl + C do strony https://jonassebastianohlsson.com/criticalpathcssgenerator/

Na tej stronie w pole:
1. URL podaję adres blog lub specyficznej strony na naszym blogu,
2. W „FULL CSS” wklejam cały nasz wygenerowany css.
3. Klikamy „Create Critical Path CSS”, po dłuższej chwili (w zależności od tego jak duży jest css w moim wypadku wszystkie połączone cssy są wielkości ponad 0,5MB) pojawia się okno textarea „CRITICAL PATH CSS” a w nim dostosowane css które kopiuję do pliku header.php od razu pod ,
oczywiście można to zrobić ładniej ale że jestem lazy to mi się nie chciało 🙂

Uwaga z tego skróconego css usuwamy wszystkie @font-face eot,ttf itd czcionki.

5. Wygląd -> Edytor -> otwieramy Funkcje motywu (functions.php)
Na samym końcu dodaję:

<?php
function remove_head_scripts() {
   remove_action('wp_head', 'wp_print_scripts');
   remove_action('wp_head', 'wp_print_head_scripts', 9);
   remove_action('wp_head', 'wp_enqueue_scripts', 1);

   remove_action( 'wp_head', 'rsd_link');
   remove_action( 'wp_head', 'wlwmanifest_link');
   remove_action( 'wp_head', 'wp_generator');
   remove_action( 'wp_head', 'start_post_rel_link');
   remove_action( 'wp_head', 'index_rel_link');
   remove_action( 'wp_head', 'adjacent_posts_rel_link');
   remove_action( 'wp_head', 'wp_shortlink_wp_head');

   add_action('wp_footer', 'wp_print_scripts', 5);
   add_action('wp_footer', 'wp_enqueue_scripts', 5);
   add_action('wp_footer', 'wp_print_head_scripts', 5);
}
add_action( 'wp_enqueue_scripts', 'remove_head_scripts' );

?>

Powyższa funkcja przenosi cały script do sekcji footer

Dodaję również jedną przydatną rzecz czyli kompresję html – usuwanie zbędnych spacji, nowych linii itd, również dodajemy w function.php na samym dole

<?php
class WP_HTML_Compression
{
    // Settings
    protected $compress_css = true;
    protected $compress_js = true;
    protected $info_comment = true;
    protected $remove_comments = true;

    // Variables
    protected $html;
    public function __construct($html)
    {
     if (!empty($html))
     {
         $this->parseHTML($html);
     }
    }
    public function __toString()
    {
     return $this->html;
    }
    protected function bottomComment($raw, $compressed)
    {
     $raw = strlen($raw);
     $compressed = strlen($compressed);
     
     $savings = ($raw-$compressed) / $raw * 100;
     
     $savings = round($savings, 2);
     
     return '<!--HTML compressed, size saved '.$savings.'%. From '.$raw.' bytes, now '.$compressed.' bytes-->';
    }
    protected function minifyHTML($html)
    {
     $pattern = '/<(?<script>script).*?<\/script\s*>|<(?<style>style).*?<\/style\s*>|<!(?<comment>--).*?-->|<(?<tag>[\/\w.:-]*)(?:".*?"|\'.*?\'|[^\'">]+)*>|(?<text>((<[^!\/\w.:-])?[^<]*)+)|/si';
     preg_match_all($pattern, $html, $matches, PREG_SET_ORDER);
     $overriding = false;
     $raw_tag = false;
     // Variable reused for output
     $html = '';
     foreach ($matches as $token)
     {
         $tag = (isset($token['tag'])) ? strtolower($token['tag']) : null;
         
         $content = $token[0];
         
         if (is_null($tag))
         {
             if ( !empty($token['script']) )
             {
                 $strip = $this->compress_js;
             }
             else if ( !empty($token['style']) )
             {
                 $strip = $this->compress_css;
             }
             else if ($content == '<!--wp-html-compression no compression-->')
             {
                 $overriding = !$overriding;
                 
                 // Don't print the comment
                 continue;
             }
             else if ($this->remove_comments)
             {
                 if (!$overriding && $raw_tag != 'textarea')
                 {
                     // Remove any HTML comments, except MSIE conditional comments
                     $content = preg_replace('/<!--(?!\s*(?:\[if [^\]]+]|<!|>))(?:(?!-->).)*-->/s', '', $content);
                 }
             }
         }
         else
         {
             if ($tag == 'pre' || $tag == 'textarea')
             {
                 $raw_tag = $tag;
             }
             else if ($tag == '/pre' || $tag == '/textarea')
             {
                 $raw_tag = false;
             }
             else
             {
                 if ($raw_tag || $overriding)
                 {
                     $strip = false;
                 }
                 else
                 {
                     $strip = true;
                     
                     // Remove any empty attributes, except:
                     // action, alt, content, src
                     $content = preg_replace('/(\s+)(\w++(?<!\baction|\balt|\bcontent|\bsrc)="")/', '$1', $content);
                     
                     // Remove any space before the end of self-closing XHTML tags
                     // JavaScript excluded
                     $content = str_replace(' />', '/>', $content);
                 }
             }
         }
         
         if ($strip)
         {
             $content = $this->removeWhiteSpace($content);
         }
         
         $html .= $content;
     }
     
     return $html;
    }
     
    public function parseHTML($html)
    {
     $this->html = $this->minifyHTML($html);
     
     if ($this->info_comment)
     {
         $this->html .= "\n" . $this->bottomComment($html, $this->html);
     }
    }
   
    protected function removeWhiteSpace($str)
    {
     $str = str_replace("\t", ' ', $str);
     $str = str_replace("\n",  '', $str);
     $str = str_replace("\r",  '', $str);
     
     while (stristr($str, '  '))
     {
         $str = str_replace('  ', ' ', $str);
     }
     
     return $str;
    }
}

function wp_html_compression_finish($html)
{
    return new WP_HTML_Compression($html);
}

function wp_html_compression_start()
{
    ob_start('wp_html_compression_finish');
}
add_action('get_header', 'wp_html_compression_start');
?>

6. Najważniejsza część pracy nad przyspieszeniem strony to oczywiście modyfikacja zdjęć.
Zdjęcia powinny mieć kompresję ustawioną na 70%, usunięcie wszystkich metadanych ze zdjęć, powinny być zapisane jako progressive, wielkość dostosowana do wielkości miejsca w którym się pojawiają zdjęcia.

7. W przyszłości zdjęcie przerobię na nowe rozwiązania dla wersji mobilnych
Więcej na https://scottjehl.github.io/picturefill/examples/demo-01.html oraz https://ericportis.com/posts/2014/srcset-sizes/

Tego rozwiązania używa między innymi theguardian.com a to wygląda mniej więcej tak (to jest jeden plik tylko że w różnych wielkościach):

<picture>
<!--[if IE 9]><video style="display: none;"><![endif]-->
<source media="(min-width: 1300px)" sizes="1300px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=1300&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=10e2200031125f835392892e9f813634 1300w">
<source media="(min-width: 1140px)" sizes="1140px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=1140&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=13d6ffcf420fb95bff93b5ca7a418f8e 1140w">
<source media="(min-width: 980px)" sizes="1125px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=1125&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=63fa2db8b2dccfc0ab408e25551c32e6 1125w">
<source media="(min-width: 740px)" sizes="965px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=965&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=c85b88b5fa49b0854485bd720d689155 965w">
<source media="(min-width: 660px)" sizes="725px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=725&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=048d9b371a22cebba3bb7dcd8e2d619c 725w">
<source media="(min-width: 480px)" sizes="645px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=645&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=97c169eb0122c0552b270a4be96e0410 645w">
<source media="(min-width: 0px)" sizes="465px" srcset="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=465&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=b4476e761590a0a1175cb66c5bfd8a8d 465w">
<!--[if IE 9]></video><![endif]-->
<img class="maxed responsive-img" itemprop="contentUrl" alt="Francesca Chaouqui" src="https://i.guim.co.uk/img/media/2fa72163af4712211cbf9abd929cc377d4af267b/0_0_4928_2957/master/4928.jpg?w=300&amp;q=85&amp;auto=format&amp;sharp=10&amp;s=c69f163a8116e3ac4ad7cc8170a1ad11">
</picture>

A poniżej wynik mojej pracy.

desctop

mobile

W webpagetest też jest bardzo pozytywnie 🙂

webpage

Zapytanie do bazy wordpress


SELECT p2c.category_id AS cat_id, COUNT(p2c.rel_id) AS numposts,
UNIX_TIMESTAMP(max(posts.post_date_gmt)) + '1' AS last_post_date,
UNIX_TIMESTAMP(max(posts.post_date_gmt)) AS last_post_date_gmt
FROM wp_post2cat p2c
INNER JOIN wp_posts posts ON p2c.post_id=posts.id
WHERE 1 = 1
AND posts.post_type = 'post' AND posts.post_status = 'publish'
AND posts.post_date_gmt <= '2014-01-21 14:33:02'
GROUP BY p2c.category_id
ORDER BY numposts DESC

Jedno zapytań do bazy wpordpress.

Dodanie przed nazwą ulicy przedrostka ul.

Dodanie w bazie danych dodać przed nazwą ulicy przedrostek „ul.”

SELECT ulica, concat('ul. ', ulica) FROM miasta_biura WHERE
ulica REGEXP '^ul.' <> 1 AND ulica REGEXP '^Al.' <> 1

UPDATE miasta_biura SET ulica = concat('ul. ', ulica)
WHERE ulica REGEXP '^ul.' <> 1 AND ulica REGEXP '^Al.' <> 1

SELECT ulica FROM miasta_biura WHERE ulica REGEXP '^ul.[^ ]'

SELECT ulica, REPLACE(ulica, 'ul.', 'ul. ') FROM miasta_biura WHERE ulica REGEXP '^ul.[^ ]'

UPDATE miasta_biura SET ulica = REPLACE(ulica, 'ul.', 'ul. ') WHERE ulica REGEXP '^ul.[^ ]'

SELECT ulica, REPLACE(ulica, 'al.', 'Al.') FROM miasta_biura WHERE ulica REGEXP '^Al.'

UPDATE miasta_biura SET ulica = REPLACE(ulica, 'al.', 'Al.') WHERE ulica REGEXP '^Al.'