Upload
tomasz-dziuda
View
2.720
Download
0
Embed Size (px)
Citation preview
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 ;-)
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": "[email protected]", "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?
@dziudek
http://dziudek.pl
http://www.slideshare.net/dziudek
Tomasz Dziuda