Electron + WordPress = ❤

Post on 21-Jan-2018

2.720 views 0 download

Transcript of Electron + WordPress = ❤

Electron + WordPress = Tomasz Dziuda

Dlaczego?

Umiem w Electrony...Źródło: https://getpublii.com

w WordPressy trochę też ...

coraz bardziej cenię swoją prywatność

Czego użyjemy?

Przyśpieszony Kurs Electrona

Źródło: https://atom.io/

Źródło: https://desktop.github.com/

=

Przyśpieszony Kurs Electrona

=

Przyśpieszony Kurs Electrona

= +

Przyśpieszony Kurs Electrona

= + +

Przyśpieszony Kurs Electrona

Przyśpieszony Kurs Electrona cz.2

Wątek główny

Przyśpieszony Kurs Electrona cz.2

Wątek główny

API systemu

Przyśpieszony Kurs Electrona cz.2

...Wątki renderujące

Wątek główny

API systemu

Przyśpieszony Kurs Electrona cz.2

...Wątki renderujące

Wątek główny

API systemu

IPC IPC IPC

Przyśpieszony Kurs Electrona cz.3

Build cross platform desktop apps with JavaScript, HTML, and CSS

Przyśpieszony Kurs Electrona cz.3

Build cross platform desktop apps with JavaScript, HTML, and CSS

XSS

Przyśpieszony Kurs Electrona cz.4

Brak możliwości ukrycia kodu źródłowego

Dlaczego WordPress?

Gotowe REST API

{REST API}GET POST PUT DELETE

Gotowy panel zarządzania

Źródło: https://www.contentful.com/

Połowa pracy za nami a jeszcze nie zaczęliśmy ;-)

1 WordPress = wiele aplikacji

Dlaczego React?

JSX

<App> <Header /> <Content /> <Footer /> <Sidebar /></App>

Ekosystem

Używają go w Automattic ;-)Źródło: https://developer.wordpress.com/calypso/

Przydatne narzędzia...mi pomogły ;-)

Postman

Źródło: https://www.getpostman.com/

Devtron

Źródło: https://electron.atom.io/devtron/

Założenia

WP Notes

WP Notes• Synchronizacja notatek po uruchomieniu/zalogowaniu

• Obsługa wielu użytkowników

• Edytor Markdown

• Możliwość dodawania, edycji i usuwania notatek

• Wyszukiwarka notatek

WP Notes• Synchronizacja notatek po uruchomieniu/zalogowaniu

• Obsługa wielu użytkowników

• Edytor Markdown

• Możliwość dodawania, edycji i usuwania notatek

• Wyszukiwarka notatek

WP Notes• Synchronizacja notatek po uruchomieniu/zalogowaniu

• Obsługa wielu użytkowników

• Edytor Markdown

• Możliwość dodawania, edycji i usuwania notatek

• Wyszukiwarka notatek

WP Notes• Synchronizacja notatek po uruchomieniu/zalogowaniu

• Obsługa wielu użytkowników

• Edytor Markdown

• Możliwość dodawania, edycji i usuwania notatek

• Wyszukiwarka notatek

WP Notes• Synchronizacja notatek po uruchomieniu/zalogowaniu

• Obsługa wielu użytkowników

• Edytor Markdown

• Możliwość dodawania, edycji i usuwania notatek

• Wyszukiwarka notatek

Implementacja

Składowe

Składowe

Odpowiednie endpointy REST API Plugin + CPT

Składowe

Odpowiednie endpointy REST API

Autoryzacja komunikacji

Plugin + CPT

JWT

Składowe

Odpowiednie endpointy REST API

Autoryzacja komunikacji

Aplikacja napisana w Electronie

Plugin + CPT

JWT

Electron + React

Endpointy i CPT

Plugin dla aplikacji

Plugin dla aplikacji

• Tworzy dedykowany Custom Post Type dla danych

• Tworzy potrzebne endpointy

• Modyfikuje istniejące endpointy

Plugin dla aplikacji

• Tworzy dedykowany Custom Post Type dla danych

• Tworzy potrzebne endpointy

• Modyfikuje istniejące endpointy

Plugin dla aplikacji

• Tworzy dedykowany Custom Post Type dla danych

• Tworzy potrzebne endpointy

• Modyfikuje istniejące endpointy

Dlaczego Custom Post Type?

Dlaczego Custom Post Type?

• Możemy na jednym WordPressie oprzeć kilka aplikacji

• CPT mogą mieć własne endpointy

• Możemy te endpointy bez obaw dostosować do swoich potrzeb

Dlaczego Custom Post Type?

• Możemy na jednym WordPressie oprzeć kilka aplikacji

• CPT mogą mieć własne endpointy

• Możemy te endpointy bez obaw dostosować do swoich potrzeb

Dlaczego Custom Post Type?

• Możemy na jednym WordPressie oprzeć kilka aplikacji

• CPT mogą mieć własne endpointy

• Możemy te endpointy bez obaw dostosować do swoich potrzeb

Endpointy

/wp-json/wp/v2/wp-notes

$args = array(// ...'show_in_rest' => true,'rest_base' => 'wp-notes'

);

register_post_type( 'wp_notes', $args );

/wp-json/wp-notes/v1/notes?author=X

[ { "id": 36, "modificationDate": 1495370276000 }, ... { "id": 13, "modificationDate": 1495295589000 }, { "id": 9, "modificationDate": 1495368831000 }]

https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/

Posty prywatne są przydatne ;)

Pobieranie prywatnych postów

1) Musimy być autoryzowani jako twórca wpisu

2) W URL-u REST API dodajemy:

wp-json/wp/v2/wp-notes/?status=private

Pamiętajmy o strefach czasowych

CEST UTC

:-(

[ { ... "date_gmt": "2017-05-21T12:37:56", ... "modified_gmt": "2017-05-21T12:37:56", ... }]

new Date().getTime() // Zwraca czas UTC

Modyfikacje endpointów

function dziudek_wp_notes_use_raw_content( $data, $post, $request ) { $data->data['content']['plaintext'] = $post->post_content; $data->data['title']['plaintext'] = $post->post_title; $data->data['modified_gmt'] = strtotime($post->post_modified_gmt . ' UTC') * 1000; return $data;}

add_filter( 'rest_prepare_wp_notes', 'dziudek_wp_notes_use_raw_content', 10, 3 );

function dziudek_wp_notes_use_raw_content( $data, $post, $request ) { $data->data['content']['plaintext'] = $post->post_content; $data->data['title']['plaintext'] = $post->post_title; $data->data['modified_gmt'] = strtotime($post->post_modified_gmt . ' UTC') * 1000; return $data;}

add_filter( 'rest_prepare_wp_notes', 'dziudek_wp_notes_use_raw_content', 10, 3 );

function dziudek_wp_notes_use_raw_content( $data, $post, $request ) { $data->data['content']['plaintext'] = $post->post_content; $data->data['title']['plaintext'] = $post->post_title; $data->data['modified_gmt'] = strtotime($post->post_modified_gmt . ' UTC') * 1000; return $data;}

add_filter( 'rest_prepare_wp_notes', 'dziudek_wp_notes_use_raw_content', 10, 3 );

function dziudek_wp_notes_use_raw_content( $data, $post, $request ) { $data->data['content']['plaintext'] = $post->post_content; $data->data['title']['plaintext'] = $post->post_title; $data->data['modified_gmt'] = strtotime($post->post_modified_gmt . ' UTC') * 1000; return $data;}

add_filter( 'rest_prepare_wp_notes', 'dziudek_wp_notes_use_raw_content', 10, 3 );

Autoryzacja

Źródło: https://jwt.io/

Źródło: https://jwt.io/

Dane w tokenie NIE SĄ szyfrowane

Przy komunikacji z REST API korzystaj z połączenia SSL

Źródło: https://pl.wordpress.org/plugins/jwt-authentication-for-wp-rest-api/

Gdy JWT nie działają dodaj w .htaccess:

RewriteEngine onRewriteCond %{HTTP:Authorization} ^(.*)RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]

Czasem może też być potrzebne dodanie:

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

Autoryzacja - krok 1Wysyłamy zapytaniem POST do endpointa /wp-json/jwt-auth/v1/token login i hasło użytkownika, którego chcemy autoryzować:

{ username: 'admin', password: 'password'}

Autoryzacja - krok 1Wysyłamy zapytaniem POST do endpointa /wp-json/jwt-auth/v1/token login i hasło użytkownika, którego chcemy autoryzować:

{ username: 'admin', password: 'password'}

{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ...", "user_display_name": "admin", "user_email": "admin@localhost.dev", "user_nicename": "admin"}

Gdy dane są poprawne otrzymujemy token i dane użytkownika:

Autoryzacja - krok 2

Do każdego zapytania wymagającego autoryzacji dodajemy nagłówek:

Authorization: Bearer WARTOŚĆ_TOKENA

Aplikacja

Struktura aplikacji

<App>

Struktura aplikacji

<App>

<Editor><Sidebar>

Struktura aplikacji

<App>

<Editor><Sidebar>

<Search>

<List><ReactMarkdown>

Struktura aplikacji

<App>

<Editor><Sidebar>

<Search>

<List>

<Item>

<ReactMarkdown>

<Item>

<Item>

Komunikacja pomiędzy komponentami

Wzorzec obserwatoraclass EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... }}

Wzorzec obserwatoraclass EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... }}

Wzorzec obserwatoraclass EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... }}

Wzorzec obserwatoraclass EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... }}

Wzorzec obserwatoraclass EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... }}

class App extends React.Component

class App extends EventEmitter

Wzorzec obserwatoraclass EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... }}

class App extends React.Component

class App extends EventEmitter

<App>

<Editor><Sidebar>

<Search>

<List>

<Item>

<ReactMarkdown>

<Item>

<Item>

<App>

<Editor><Sidebar>

<Search>

<List>

<Item>

<ReactMarkdown>

<Item>

<Item>

<App>

<Editor><Sidebar>

<Search>

<List>

<Item>

<ReactMarkdown>

<Item>

<Item>

subscribe('delete-item', callback)

<App>

<Editor><Sidebar>

<Search>

<List>

<Item>

<ReactMarkdown>

<Item>

<Item>

distpatch('delete-item', itemID)

Przechowywanie danych

Przechowywanie danychuser_ID_1 1.md 2.md 3.md files.json

user_ID_2 4.md 5.md files.json

Przechowywanie danychuser_ID_1 1.md 2.md 3.md files.json

user_ID_2 4.md 5.md files.json

[ {

id: 10, title: "Post title", modificationDate: 123049044

}, {

id: 10, title: "Post title", modificationDate: 123049044

}, ...

]

Przechowywanie danychfiles.jsonuser_ID_1

1.md 2.md 3.md files.json

user_ID_2 4.md 5.md files.json

Synchronizacja danych

Pobranie danych z endpointa synchronizacji

dziudek-wp-notes/1/ 1.md 2.md 3.md files.json

[{"id": 1,"modificationDate": 102

}, {"id": 4,"modificationDate": 105

}]

wp-json/wp-notes/v1/notes?author=1

Porównanie dat modyfikacji postów

[{"id": 1,"modificationDate": 102

}, {"id": 4,"modificationDate": 105

}]

[{"id": 1,"modificationDate": 101

}, {"id": 2,"modificationDate": 102

},{"id": 3,"modificationDate": 103

}]

Lokalnie Zdalnie

Usunięcie nieistniejących plików

dziudek-wp-notes/1/ 1.md 2.md 3.md files.json

[{"id": 1,"modificationDate": 102

}, {"id": 4,"modificationDate": 105

}]

Pobranie i zaktualizowanie zmienionych wpisów

dziudek-wp-notes/1/ 1.md 4.md files.json

[{"id": 1,"modificationDate": 102

}, {"id": 4,"modificationDate": 105

}]

Zaktualizowanie pliku files.json

dziudek-wp-notes/1/ 1.md 4.md files.json

[{"id": 1,"modificationDate": 102

}, {"id": 4,"modificationDate": 105

}]

Pobieranie danych: node-fetch

Źródło: https://github.com/bitinn/node-fetch

Fetch API: https://developers.google.com/web/updates/2015/03/introduction-to-fetch

fetch('http://httpbin.org/post', { method: 'POST', body: stream }) .then(res => res.json()) .then(json => console.log(json));

Edytor

Źródło: https://github.com/JedWatson/react-md-editor

render: function() {return <Editor

value={this.state.code} options={configObject} onChange={this.updateCode} />

}

Źródło: https://codemirror.net/

Skróty klawiaturoweimport {remote} from 'electron';

const template = [{ label: "Edit", submenu: [{ label: "Zapisz zmiany", accelerator: "CmdOrCtrl+S", click: function() { // .. } ]}];

const menu = remote.Menu.buildFromTemplate(template);remote.Menu.setApplicationMenu(menu);

DEMO

Co dalej?

Offline mode

Generowanie PDF-ówlet win = new BrowserWindow({width: 800, height: 600})win.loadURL('file://file-to-load.html')

win.webContents.on('did-finish-load', () => { win.webContents.printToPDF({}, (error, data) => { fs.writeFile('/tmp/print.pdf', data, (error) => { console.log('Write PDF successfully.') }); });});

Bezpieczne przechowywanie tokenów

node-keytar

Źródło: http://atom.github.io/node-keytar/

Natywny moduł do przechowywania haseł z użyciem Keychain (macOS),

Credential Vault (Windows) i libsecret (Linux)

Do przejrzenia

• https://nodesource.com/blog/fifteen-essential-packages-to-get-started-with-electron/

• https://openfin.co/2016/11/04/openfin-slashes-electron-memory-78/

• http://blog.atom.io/2017/04/18/improving-startup-time.html

• https://openfin.co/2016/02/17/openfin-addressing-security-and-performance-challenges-with-electron/

• https://github.com/pojala/electrino

• https://github.com/MacGapProject/MacGap1

Plugin: https://github.com/dziudek/WordCampPolska-WP-Notes-Plugin

Aplikacja: https://github.com/dziudek/WordCampPolska-WP-Notes-App

Artykuły warte uwagi:

Pytania?

tomasz@dziuda.com

@dziudek

http://dziudek.pl

http://www.slideshare.net/dziudek

Tomasz Dziuda