Heyho impartial hipster blackberry!

: Clippy, bash / zsh commands, CSS Color

Clippy

CSS

  • color-mix(in srgb, red 25%, blue)

CSS x JS

  • change custom property on :root/html: document.documentElement.style.setProperty(--var-name, val)

CSS Color

/* alpha syntax */
color: rgba(255, 0, 255 / 75%); /* vs. rgba(…) */
color: rgba(255, 0, 255 / .75);

/* (HDR) color modes */
color: color(display-p3 1 0 1); /* vs. #F0F */

/* new color functions */
color: oklch(71.5% 0.35 330); /* vs. #F0F */

/* utilities */
color: color-mix(in lch, #F0F, white 20%);

/*
 * keep a tab on …  
 */

/* relative color syntax */
color: lch(from #F0F l calc(c + 75) h); /* increaces chroma by 75 */

/* color contrast */ 
color: color-contrast(var(--bg) vs #F0F, hotpink); /* pick the color that contrasts the most with --bg, choose between #F0F and hotpink)

VIM basics

  • Exiting: :q,
    • modified/force: :q!
    • write changes + quit :wq
  • Modes:
    • Insert (i)
      • esc back to normal mode
      • +p paste from clipboard
    • Command (:)
    • Visual (v)
  • Deleting
    • character: x
    • line dd
  • Undo: u
  • Saving: :w
  • Commnads
    • Go to line 2 :2
    • running shell command :!<command>
  • Settings
    • show linenumbers :set number

Source

resources clipboard 📋

PHP Clipboard

Random selected notes regarding PHP

  • use str_contains to check if a string contains a string (instad of strpos) (8.x)
  • named parameters allows parameter supply in any order
    • function someFunc(string $value, array $options) -> someFunc(options: $opt, value: $val)

Vue Basics (Worksheet)

Resources & Infos

Terminology

  • State Management => All data in one place = Store = Single-Source-of-Truth
  • SPA / MPA – Single Page Application / Multi Page Application

Vue root instance

new Vue({
   el: '#app',
   data: {
     // supplied data
     entries: datahere
   },
   computed: {
     // computed data, will be updated if data changes
   },
   methods: {
     // custom functions
   }
})
<!-- SCOPE: -->
<div id="app">
   <!-- accessible by vue -->
</div>
<div id="something">
   <!-- NOT accessible by vue -->
</div>
(mehr …)

Support/feature testing in JS

Method/Property

if ("method" in object) {...}

// Example (from MDN):
if("geolocation" in navigator) { ... }

Feature test

(from modernizr)

const hasSomeFeature = () => {
  try {
    // test something, eg. write to localStorage.
    return true;
  } catch(e) {
    return false;
  }
}

Check if element has property

Create an instance of the Element in memory and test the porperty

if (!!document.createElement('element').property) {...}

// Example (from MDN):
function supports_canvas() {
return !!document.createElement('canvas').getContext;
}

if(supports_canvas()) { ... }

Remidner: !! returns the truthy value (bool).

→ MDN

CSS Feature support

equivalent of CSS’s @supports(property: value).

CSS.supports("property", "value")

→ MDN

Media Query

equivalent of CSS’s @media

window.matchMedia('(max-width: 600px)');

check match with .matches (bool):

const mq = window.matchMedia('(max-width: 600px)');

// Checking for matches:
if (mq.matches) {
  // media query matches!
}

// Listening for matches:
mq.addEventListener('change', e => {
  if (e.matches) {
    // ...
  }
});

Careful: At the time of writing the addEventListener example does not work in Safari and IE, see browser compatibility table (MDN).

→ MDN, in depth: CSS Ttricks

Link mixing bowl

Data

Testig & Security

More

Scala on macOS / OSX

Install (w. homebrew)

  1. First, check if the reqired Java version is instaled java --version . Scala requires at least Version 1.8.
    If not, install AdoptOpenJDK with Homebrew Cask: brew cask install adoptopenjdk
  2. Install scala: brew install scala
  3. Verify with scala -version or running directly scala and outputting something like println("Moshi moshi").

Run script files

First compile with scalac providing filename/-path (including extension). This generates a file with the class name in the folder defined in the package entry (or, if omitted, in the same as the scala file) then run it by calling scala followed by the method name (without extension)

scalac script.scala
scala script

Scriptfile anatomy

// package name
package ch.lrnz.example // binary will be generated in ch/lrnz/example

// imports
import import ch.lrnz.example.Functions // all, as 'package'
import import ch.lrnz.example.Utils._   // all, as single classes/methods
import java.util.Date


object myObject {

  def main(args:Array[String]): Unit = {
      // Void. 
      // Needed somehow? Otherwise: Compiling Error.
  }

  def myMethod(param1:Double,param2:Double):Double = {
    // do sth and be sure to return a Double.
  }

}

ImageMagick (command line)

To get started

Compressing

magick source.jpg -strip -interlace Plane -gaussian-blur 0.05 -quality 60% result.jpg

source

Batch processing (=> mogrify)

mogrify -quality 60 -density 72 -strip -resize 2500x1500\> -path ../foto-compressed *.jpg

In prose: This example sets the image quality to 60% and the dpi to 72, strips exif infos et al (only for png?) resizes the image if dimensions are bigger than 2500px w or 1500px heigh (keeping the aspect ratio [default]) and saving the news files at the specified (here: relative) path

Note the difference between the -densinty and the -resample option.

Combining

blend modes

-compose <blendmode>

convert img1.png imgN.png -compose multiply -composite imgOut.png

Note: whithout -composite, every layer would be outputet separately

List all blend modes with identify -list compose

Source

opacity

convert img1.png \( img2.png -alpha set -channel A -evaluate set 60% \) -composite imgOut.png

or:

convert img1.png \( img2.png -normalize +level 0,60% \) -composite imgOut.png

(not tested). Source

Copy text from a website (w/ console)

list items text

Copies the inner Text of a list (ordered or unordered) to the clipboard, one item per line.

Select the <ul> or <ol> element in the inspector, then run the following code in the console:

copy(Array.from($0.querySelectorAll('li'), el => el.innerText).join('\r\n'));

Explainer: Selects all <li> elements of the selected parent ($0), converts it to an Array (Array.from()since the returned node list is map‚able), get the innerText of those elements via map, the second parameter of Array.from(), join the Array to a Line-by-line string-list (otherwise we would get an array markup), then copy everything to clipboard.

Adapt to your own needs, e.g replace 'li' with 'img' and el.innerText with el.src to get all image urls.

notes

👉 wrap code inside an IIFE in order to re-run it without an … alreay declared error:

(() => {
  // function here
})();

Multiply conent for prototyping

A few strategies to «generate» (or rather multiply) content with JS.

repeat() existing content

Just copy/paste the contetn x times.

<div id="grid">
    <div class="item">
         ...
    </div>
</div>
const container = document.getElementById('grid');
container.insertAdjacentHTML('beforeend',container.innerHTML.repeat(3) );

populate <template />

Use template-tags and replace %placeholders% with data.

<template id="exampleTemplate">
    <section>
        <h1>%1%</h1>
        ...
    </section>
</template>

<div id="dynamicContent"></div>
const expandTemplate = (id, data) => {
	const template = document.querySelector(`#${id}`);
	const target = document.querySelector('#dynamicContent');
	
	data.forEach((dataPoint, index) => {
		const instance = document.importNode(template.content, true);
		
		// replace 
		const section = instance.querySelector('section');
		section.innerHTML = section.innerHTML.replace( '%1%', dataPoint ); 

		target.appendChild(instance);
	});

}

expandTemplate( 'exampleTemplate', ['Hello', 'World', 'Data'] );

<custom-HTML-tags /> + <template />

<template id="exampleTemplate">
    <section>
        ...
    </section>
</template>

<custom-section foo="bar"></custom-section>
<custom-section foo="doo"></custom-section>
class CustomSection extends HTMLElement {
    connectedCallback() {
		
        if (this.hasAttribute('foo')) {
            const fooAtt = this.getAttribute('foo');
        }
		
        // use template
        const template = document.querySelector('#exampleTemplate');
        const instance = document.importNode(template.content, true);

        // get content of instance – here the section tag:
        // const section = instance.querySelector('section');
        // do something with section ...

        this.appendChild(instance);
	}
}

customElements.define('custom-section', CustomSection);

per tag style

(whithout shadow dom)

Collect styles from custom attributes and bundle them into a stylesheet.

<custom-section customStyle="background:salmon;color:white;"></custom-section>
<custom-section customStyle="background:rose;color:black;"></custom-section>
// function for appending custom style-sheet
const appendStyle = styles => {
    let css = document.createElement('style');
    css.type = 'text/css';

    if (css.styleSheet){
        css.styleSheet.cssText = styles;
    }else{
        css.appendChild(document.createTextNode(styles));
    } 

    document.getElementsByTagName("head")[0].appendChild(css);
}

let styles="";

class CustomSection extends HTMLElement {
    connectedCallback() {
        // generate random ID
        const randID = Math.ceil(Math.random() * 100000);
        const id = `s-${randID}`;
        
        if(this.hasAttribute('customStyle')) {
            styles += `
                #${id}{ 
                    ${this.getAttribute('customStyle')} 
                }`;
        }

        // append template as in preceding example ... 

    }
}

customElements.define('custom-section', CustomSection);

// append styles
appendStyle(styles);

Notes on greener Websites

Notes from Tom Greenwood: Zero Carbon Emission talk (WordCamp Europe 2017)

  • Internet carbon emission is approx. the same as Germany or Turkey (the worlds 6. in electicity use [behind CN, US, India, Japan, Russia]) with a total emisson of 300 milion tonns of CO2 [2016/17]
  • WordPress makes up for about 27% of the Internet [2017]
  • The main electricity culprits are probably streaming services linke YouTube, Amazon Prime …
  • Reduce Filesize, cache, remove unused files (media library)
    • Because data = energy = carbon
    • cache: plugin (wp super cache / w3total) and server-side (varnish)
  • «Carbon offset» = (financially) compensate for energy usage / co2 emission by supporting renewable energy (companies) or the reduction of co2

Literature

  • Designing for sustainability

Links

Intersection Observer

lazy-loading example

HTML (note: 1x1px spacer gif as src)

<img class="lazy-img"  src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="lazyDog.jpg">
<img class="img lazy-img" ... >

JS:

const ioOpt = {
    // root: null,
    // threshold: 0.2
}

const ioCallback = (entries, observer) =>{
    entries.forEach( entry => {
        const img = entry.target;

        if( entry.intersectionRatio > 0 ){
            img.src = img.dataset.src;
            observer.unobserve( img );      
        }
        
    } );
} 

const observer = new IntersectionObserver( ioCallback, ioOpt);

const targets = document.querySelectorAll(".lazy-img");
targets.forEach( target => {
    observer.observe(target);
} );

Notes:

  • Options: if root ist omitted or null, the viewport is used as the root element
  • Options: threshold 0.0 – 1.0 how much (percentage) of the target hast to be intersecting with the root to fire the callback
  • To know if the content is above or below, compare if entry.boundingClientRect.y is greater/lesser than entry.rootBounds.y.

wp-cli

Install

see: https://www.cyon.ch/blog/Mit-WP-CLI-WordPress-auf-der-Kommandozeile-verwalte

Troubleshooting section at the bottom of the page

Commands

  • wp plugin update [options below]
    • <plugin-name(s)>
    • --all : updates all plugins
    • --dry-run : Preview which plugins would be updated.
    • --exclude=<pluin-name(s)>
  • wp core check-update and wp core update
  • wp option get blog_public
    • checks if blog is search engine crawlable, returns 1 or 0.
    • append 1 to enable, 0 to disable
  • wp config get
    • reads out wp config file
  • wp core version
    • Returns current version number of WP install
  • wp core verify-checksums
    • Verify md5 checksums against current version on WordPress.org
    • --version=4.9.9 : Check for specific version
  • wp search-replace '//temporarydomain.com' '//finaldomain.com'
    • Search + replaces database entries
    • Always use --dry-run first to prevent f*#©<ups

See: Handbook

Aliases

Install wp-cli locally, then add the aliases as follows to the wp-cli/config.yml

@aliasname
    ssh: user@server/path/to/wp
@otheralias
    ssh:otheru@others/path/to/wp
@aliasgroup
    - @aliasname
    - @otheralias

Usage: wp <aliasname|group|@all> <command>.

Examples:

  • wp @otheralias core check-update
  • wp @all option get blog_public

See: WP-Cli Commands Handbook | Jason Yingling

wp-cli + Alfred App

Alfred app:

  • Create a workflow with an external trigger
  • Copy the sample code
  • escape the quotes (\")

Terminal Command Action

v=$(wp @nekos core version);
/usr/bin/osascript -e "tell application \"Alfred 3\" to run trigger \"myTrigger\" in workflow \"ch.lnrz.wphelpers\" with argument \"$v\""
  • v=$(wp @nekos core version); runs the comands and stores it to the variable v
  • /usr/bin/osascript -e "tell ... executes apple script which calls the external trigger myTrigger of the workflow ch.lnrz.wphelperswith the argument of the variable v
    • Note: the actionscript command must be wrapped in quotes (thus the escaping beforhand)

Trouble shooting

Tab completition in zsh

Symptom: comand nof found: complete

For Tab completion in zsh use the following lines in the .zshrc or the sourced .bash_profile [s]:

autoload bashcompinit
bashcompinit
source ~/.wp-cli/wp-completion.bash

Trouble with remote $PATH

Symptom:command not found: wp

See: Making WP-CLI accessible on a remote server (WP Handbook)
=> third solution (before_ssh) worked for me (dont forget the <?php ... ?> Tags in the included file)


CodeKit extensions

Uglify for ES6+

Reason: The built in uglify lib does not support ES6+ and throws an error if it stumbles upon something like const.

Solution: Use the uglify harmony branch (uglify-es) instead via a CodeKit hook

  1. Check if uglify-es ist already installed: npm list -g uglify-es . If not install it globaly: npm install uglify-es -g (see the harmony repository )
  2. Add a new hook in the CodeKit project peferences to run a shell script on any file which inputFileName ends with .js
  3. Use the following script to compress and mangle this file  uglifyjs $CK_INPUT_PATH --compress --mangle -o $CK_OUTPUT_PATH

See the Comandline Usage section of the uglify-es repo for more options and the CodeKit hook help for constants for the CodeKit part of the deal.


SSH

generate (macOS)

  • Terminal: run ssh-keygen
  • use default location
  • list keys: ls ~/.ssh
  • copy key with: cat ~/.ssh/id_rsa.pub | pbcopy
  • Add key to ssh-agent (so the passphrase doesn’t have to be typed in every single time)
    • Start Agent: eval ssh-agent
    • ssh-add -K ~/.ssh/<private key>
    • write to config file code ~/.ssh/config :
Host *
  seKeychain yes
   AddKeysToAgent yes
   IdentityFile ~/.ssh/id_rsa

see: Atlassian

add to server

ssh-copy-id user@server

=> Client public key will be copied to server’s location ~/.ssh/authorized_keys

connect to server

ssh user@server

CSS Layout (picks)

Grid

grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  • repeat( how-many-times , column-size )
  • auto-fill/auto-fit keyword as first value of repeat() (instead of int): place as many items as possible (defined by their (min-)width) on the row, otherwise wrap them on the next row.
    • fill: let items grow in with to fill up the available spacefit: use (min-)widht of item, remaining space will be left as white space at the end of the row
  • minmax( min max ) as second repeat() valueitem min with in pixel as min-value: «don’t let the item get smaller than this»
    1fr as max-value: «let item be max 1 fraction of the available space», together with the auto-fill keyword this means: «let item be as big as possible within the condition of fitting as many items on the row as possible»

Demo

Disabling & changing default Gutenberg features

Only allow certain types of blocks (aka ‚remove‘ blocks)

👉  allowed_block_types hook

add_filter( 'allowed_block_types', 'slug_allowed_block_types' );
 
function slug_allowed_block_types( $allowed_blocks ) {
 
	return array(
		'core/image',
		'core/paragraph',
		'core/heading',
		'core/list'
	);
 
}

Takes $post as a second parameter, so the allowed blocks can be set on a per post-type basis

add_filter( 'allowed_block_types', 'slug_allowed_block_types', 10, 2 );
 
function slug_allowed_block_types( $allowed_blocks, $post ) {
 
	$allowed_blocks = array(
		'core/image',
		// ...
	);

 
	if( $post->post_type === 'page' ) {
		$allowed_blocks[] = 'core/shortcode';
	}
 
	return $allowed_blocks;
 
}

Note:

  • block list is empty on default
  • allowed blocks per template via if( 'page-template-name.php' == get_page_template_slug( $post ){ ... } but is only aplied when page with template already has been saved.
  • for block slug see Misha Rudrastyhs collection

Source: Misha Rudrastyh: Removing Default Gutenberg Blocks

Disable default WP block styles

function slug_remove_gutenberg_default_styles() {
	if( !is_admin() ){
		wp_dequeue_style( 'wp-block-library');
	}
}
add_action( 'wp_print_styles', 'slug_remove_gutenberg_default_styles' );

(duplicate of Gutenberg notes entry)

Disable color palettes

// Disable color palette.
add_theme_support( 'editor-color-palette' );

// Disable color picker.
add_theme_support( 'disable-custom-colors' );

Note: As with all add_theme_support methods hook into after_setup_theme

Source: Theme Coder

Block Templates

Predefined blocks per post type.

function slug_add_template_to_page() {
	$post_type_object = get_post_type_object( 'page' );	
	
    $post_type_object->template = array(
        array( 'core/paragraph', array(
            'placeholder' => 'Add Description...',
		) ),
		array( 'core/image', array(
        ) ),
    );
    $post_type_object->template_lock = 'all';
}
add_action( 'init', 'slug_add_template_to_page' );
  • ->template-lock :
    • 'all' : prevents all block manipulation (changing order adding, removing)
    • 'insert' : prevents inserting or removing blocks but allows chaning the order

Block Templates

See also

Gutenberg Dev

Follwing along Zac Gordons Gutenberg Development Course.

Insert:

The Gutenbergs JS libraries

  • wp.element: Abstraction Layer on top of React and React Dom. Used for creating elements inside blocks.
  • wp.blocks: Components and functions for building blocks.
  • wp.components: Components that can be used for building interfaces within the editor (tooltips, buttons … )
  • wp.i18n: For translations, similar to the __() methods in php

All of these libs are accessible globaly (e.g. through the console or other scripts)
To access them within code, use something like

const { __ } = wp.i18n; // using deconstruction

Basic block architecture

Default roadmap:

  1. Enque block JS in main plugin/theme file [php]
  2. Register block using registerBlockType() [js]
  3. Opt. break up block code in components [js]
  4. Enque block css [php]

Enque block js + css

  • enque_block_edtior_assets: hook for enquing block js+css in the editor (not the frontend). Used to enque the main block js file, or editor-only styles.
  • enque_block_assets : hook to enque (mostly) css (and js) for both, the editor and the front endUser for main block styles. Use !is_admin()for front-end-only styles/scripts 

Building blocks

registerBlockType()

wp.blocks.registerBlockType(
  'plugin-name/block-name',
  {
    title: wp.i18n.__('Blocktitle', 'textdomain),
    description: '...',
    category: 'common',
    icon: 'wordpress-alt',
    keywords: [wp.i18n.__('Demo', 'textdomain)],
    supports: { html: false },
    attributes: {} ,
    edit: () => {},
    save: () => {}
  }
);

attributes

Which information to (re-)store and manipulate

attributes {
  message: {
    type: "array",
    source: "children",
    selector: ".classname-of-element"
  },
}

edit

Controls how the block is rendered (and updated) in the editor.
Usualy constists of a return method as well as a method that handles what hapens onChange (e.g. text editing). props ( React, anyone?) are passed on automatically from WP.

edit: props => {
  const {
    attributes: { message },
    className,
    setAttributes
  } = props;
  const onChangeMessage = message => {
    setAttributes({ message });
  };
  return {
    <div className={className}>
      <RichText
        tagName="div"
        multiline="p"
        placeholder={__("Type something ...", "textdomain")}
        onChange={onChangeMessage}
        value={message}
      />
    </div>
  }
}

save

How to save the post – for displaying on the front end and restoring for the editor.

save: props => {
  const {
    attributes: { message }
  } = props;
  return (
    <div>
      <div class="output-feld">{message}</div>
    </div>
   );
}

Update attributes on change

attributes: {
  content: {
    ...
  }
}
edit: props => {
  const { attributes: { content }, setAttributes } = props;
  ...
  return ( 
    <RichText
       ...
       onChange={ content => { setAttributes( { content } ) } }
       value={ content }
    >
);

Data API

wp.data.<STORE_NAME> (stores: „core/editor“, „core/blocks“, „core/editor“ …, to check them out log wp.data.select("<STORE_NAME>") [or dispatch instead of select])
(import: const { <STORE_NAME> } = wp.data)

select

=> get data

select("core/editor").getBlockCount();

subscribe

=> subscribe/listen to status change

subscribe(() => {
  // updated every time the block count changes
  const blockCount = select("core/editor").getBlockCount();
});

Note: subscribe returns a unsubscribe function

const unsubscribe = subscribe(()=>{ /* ... */ });
unsubscribe();

Advanced

Subscribe Class to controll the state handling (otherwise you might want to use withSelect) – more Reactish, less WP abstraction

const { Component } = wp.element;
const { select, subscribe } = wp.data;

    
export default class SubscribeDemo extends Component{

    state = {
        blockCount: "",
    }

    componentDidMount() {
        const unsubscribe = subscribe( () => {
            const blockCount = select("core/editor").getBlockCount();
            this.setState({blockCount});     
        } );
    }

    render() {
        return <p>Block count: {this.state.blockCount}</p>
    }
    
}

Key-Points:

  • Extend the Component class (imported from wp.element)
  • Manage state object ( => React )
    • call with this.state
    • update with this.setState() [see: React]
  • uses componentDidMount()method [see: React]
  • use Reacts render() function

withSelect

=> HOC [?] for select, similar to subscribe it will update everytime its values changes

As component:

const WithSelectDemo = ({ blockCount }) => (
    <p>Block Count: {blockCount}</p>
)
export default withSelect( (select, ownProps) => {
    return {
        blockCount: select("core/editor").getBlockCount()
    }
} )(WithSelectDemo);

Explanation / How to read

First code block: Create <WithSelectDemo /> component that takes the current block count as an argument (and prints it)

Second code block: Export withSelect()(WithSelectDemo):

  • when <WithSelectDemo />is exported/used …
  • it will wrapp everything inside of withSelect()
  • callselect() (getting the block count) …
  • create / asign it to a new variable blockCount
  • and make that variable available to the <WithSelectDemo /> component (which takes it as its argument)

ownProps

Notice the ownProps parameter for the withSelect()above. It will get all props (think: attributes) passed into the component (and can be passed on to the component, of course)

<WithSelectDemo text="blah" />

export default withSelect( (select, ownProps) => {
    console.log(ownProps) // logs: {text: "blah"}
    return {
        ...
    }
...

dispatch

=> calling an action

dispatch( "core/editor" ).removeBlock( clientID ) // clientID = BlockID

withDispatch

=> HOC [?] for dispatch

//TODO

compose

=> HOC [?] for combining multiple HOC’s (Takes an array of HOCs and returns a new component)

// Todo