Successfully reported this slideshow.
Your SlideShare is downloading. ×

Electron + WordPress = ❤

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad

Check these out next

1 of 117 Ad
Advertisement

More Related Content

Slideshows for you (20)

Similar to Electron + WordPress = ❤ (20)

Advertisement
Advertisement

Electron + WordPress = ❤

  1. 1. Electron + WordPress = Tomasz Dziuda ❤
  2. 2. Dlaczego?
  3. 3. Umiem w Electrony... Źródło: https://getpublii.com
  4. 4. w WordPressy trochę też ...
  5. 5. coraz bardziej cenię swoją prywatność
  6. 6. Czego użyjemy?
  7. 7. Przyśpieszony Kurs Electrona
  8. 8. Źródło: https://atom.io/
  9. 9. Źródło: https://desktop.github.com/
  10. 10. = Przyśpieszony Kurs Electrona
  11. 11. = Przyśpieszony Kurs Electrona
  12. 12. = + Przyśpieszony Kurs Electrona
  13. 13. = + + Przyśpieszony Kurs Electrona
  14. 14. Przyśpieszony Kurs Electrona cz.2 Wątek główny
  15. 15. Przyśpieszony Kurs Electrona cz.2 Wątek główny API systemu
  16. 16. Przyśpieszony Kurs Electrona cz.2 ... Wątki renderujące Wątek główny API systemu
  17. 17. Przyśpieszony Kurs Electrona cz.2 ... Wątki renderujące Wątek główny API systemu IPC IPC IPC
  18. 18. Przyśpieszony Kurs Electrona cz.3 Build cross platform desktop apps with JavaScript, HTML, and CSS
  19. 19. Przyśpieszony Kurs Electrona cz.3 Build cross platform desktop apps with JavaScript, HTML, and CSS XSS
  20. 20. Przyśpieszony Kurs Electrona cz.4 Brak możliwości ukrycia 
 kodu źródłowego
  21. 21. Dlaczego WordPress?
  22. 22. Gotowe REST API {REST API} GET POST PUT DELETE
  23. 23. Gotowy panel zarządzania
  24. 24. Źródło: https://www.contentful.com/
  25. 25. Połowa pracy za nami a jeszcze nie zaczęliśmy ;-)
  26. 26. 1 WordPress = wiele aplikacji
  27. 27. Dlaczego React?
  28. 28. JSX <App> <Header /> <Content /> <Footer /> <Sidebar /> </App>
  29. 29. Ekosystem
  30. 30. Używają go w Automattic ;-) Źródło: https://developer.wordpress.com/calypso/
  31. 31. Przydatne narzędzia ...mi pomogły ;-)
  32. 32. Postman Źródło: https://www.getpostman.com/
  33. 33. Devtron Źródło: https://electron.atom.io/devtron/
  34. 34. Założenia
  35. 35. WP Notes
  36. 36. WP Notes • Synchronizacja notatek po uruchomieniu/zalogowaniu • Obsługa wielu użytkowników • Edytor Markdown • Możliwość dodawania, edycji i usuwania notatek • Wyszukiwarka notatek
  37. 37. WP Notes • Synchronizacja notatek po uruchomieniu/zalogowaniu • Obsługa wielu użytkowników • Edytor Markdown • Możliwość dodawania, edycji i usuwania notatek • Wyszukiwarka notatek
  38. 38. WP Notes • Synchronizacja notatek po uruchomieniu/zalogowaniu • Obsługa wielu użytkowników • Edytor Markdown • Możliwość dodawania, edycji i usuwania notatek • Wyszukiwarka notatek
  39. 39. WP Notes • Synchronizacja notatek po uruchomieniu/zalogowaniu • Obsługa wielu użytkowników • Edytor Markdown • Możliwość dodawania, edycji i usuwania notatek • Wyszukiwarka notatek
  40. 40. WP Notes • Synchronizacja notatek po uruchomieniu/zalogowaniu • Obsługa wielu użytkowników • Edytor Markdown • Możliwość dodawania, edycji i usuwania notatek • Wyszukiwarka notatek
  41. 41. Implementacja
  42. 42. Składowe
  43. 43. Składowe Odpowiednie endpointy REST API Plugin + CPT
  44. 44. Składowe Odpowiednie endpointy REST API Autoryzacja komunikacji Plugin + CPT JWT
  45. 45. Składowe Odpowiednie endpointy REST API Autoryzacja komunikacji Aplikacja napisana w Electronie Plugin + CPT JWT Electron + React
  46. 46. Endpointy i CPT
  47. 47. Plugin dla aplikacji
  48. 48. Plugin dla aplikacji • Tworzy dedykowany Custom Post Type dla danych • Tworzy potrzebne endpointy • Modyfikuje istniejące endpointy
  49. 49. Plugin dla aplikacji • Tworzy dedykowany Custom Post Type dla danych • Tworzy potrzebne endpointy • Modyfikuje istniejące endpointy
  50. 50. Plugin dla aplikacji • Tworzy dedykowany Custom Post Type dla danych • Tworzy potrzebne endpointy • Modyfikuje istniejące endpointy
  51. 51. Dlaczego Custom Post Type?
  52. 52. 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
  53. 53. 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
  54. 54. 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
  55. 55. Endpointy
  56. 56. /wp-json/wp/v2/wp-notes $args = array( // ... 'show_in_rest' => true, 'rest_base' => 'wp-notes' ); register_post_type( 'wp_notes', $args );
  57. 57. /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/
  58. 58. Posty prywatne są przydatne ;)
  59. 59. 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
  60. 60. Pamiętajmy o strefach czasowych CEST UTC :-(
  61. 61. [ { ... "date_gmt": "2017-05-21T12:37:56", ... "modified_gmt": "2017-05-21T12:37:56", ... } ] new Date().getTime() // Zwraca czas UTC
  62. 62. Modyfikacje endpointów
  63. 63. 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 );
  64. 64. 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 );
  65. 65. 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 );
  66. 66. 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 );
  67. 67. Autoryzacja
  68. 68. Źródło: https://jwt.io/
  69. 69. Źródło: https://jwt.io/
  70. 70. Dane w tokenie NIE SĄ szyfrowane
  71. 71. Przy komunikacji z REST API korzystaj z połączenia SSL
  72. 72. Źródło: https://pl.wordpress.org/plugins/jwt-authentication-for-wp-rest-api/
  73. 73. Gdy JWT nie działają dodaj w .htaccess: RewriteEngine on RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1] Czasem może też być potrzebne dodanie: SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
  74. 74. Autoryzacja - krok 1 Wysył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' }
  75. 75. Autoryzacja - krok 1 Wysył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:
  76. 76. Autoryzacja - krok 2 Do każdego zapytania wymagającego 
 autoryzacji dodajemy nagłówek: Authorization: Bearer WARTOŚĆ_TOKENA
  77. 77. Aplikacja
  78. 78. Struktura aplikacji <App>
  79. 79. Struktura aplikacji <App> <Editor><Sidebar>
  80. 80. Struktura aplikacji <App> <Editor><Sidebar> <Search> <List> <ReactMarkdown>
  81. 81. Struktura aplikacji <App> <Editor><Sidebar> <Search> <List> <Item> <ReactMarkdown> <Item> <Item>
  82. 82. Komunikacja pomiędzy komponentami
  83. 83. Wzorzec obserwatora class EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... } }
  84. 84. Wzorzec obserwatora class EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... } }
  85. 85. Wzorzec obserwatora class EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... } }
  86. 86. Wzorzec obserwatora class EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... } }
  87. 87. Wzorzec obserwatora class EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... } } class App extends React.Component class App extends EventEmitter
  88. 88. Wzorzec obserwatora class EventEmitter extends React.Component { dispatch(event, data) { ... } subscribe(event, callback) { ... } unsubscribe(event, callback) { ... } } class App extends React.Component class App extends EventEmitter
  89. 89. <App> <Editor><Sidebar> <Search> <List> <Item> <ReactMarkdown> <Item> <Item>
  90. 90. <App> <Editor><Sidebar> <Search> <List> <Item> <ReactMarkdown> <Item> <Item>
  91. 91. <App> <Editor><Sidebar> <Search> <List> <Item> <ReactMarkdown> <Item> <Item> subscribe('delete-item', callback)
  92. 92. <App> <Editor><Sidebar> <Search> <List> <Item> <ReactMarkdown> <Item> <Item> distpatch('delete-item', itemID)
  93. 93. Przechowywanie danych
  94. 94. Przechowywanie danych user_ID_1 1.md 2.md 3.md files.json user_ID_2 4.md 5.md files.json
  95. 95. Przechowywanie danych user_ID_1 1.md 2.md 3.md files.json user_ID_2 4.md 5.md files.json
  96. 96. [ { id: 10, title: "Post title", modificationDate: 123049044 }, { id: 10, title: "Post title", modificationDate: 123049044 }, ... ] Przechowywanie danych files.jsonuser_ID_1 1.md 2.md 3.md files.json user_ID_2 4.md 5.md files.json
  97. 97. Synchronizacja danych
  98. 98. 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
  99. 99. 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
  100. 100. 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 }]
  101. 101. Pobranie i zaktualizowanie zmienionych wpisów dziudek-wp-notes/1/ 1.md 4.md files.json [{ "id": 1, "modificationDate": 102 },
 { "id": 4, "modificationDate": 105 }]
  102. 102. Zaktualizowanie pliku files.json dziudek-wp-notes/1/ 1.md 4.md files.json [{ "id": 1, "modificationDate": 102 },
 { "id": 4, "modificationDate": 105 }]
  103. 103. 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));
  104. 104. Edytor Źródło: https://github.com/JedWatson/react-md-editor render: function() { return <Editor value={this.state.code} options={configObject} onChange={this.updateCode} /> }
  105. 105. Źródło: https://codemirror.net/
  106. 106. Skróty klawiaturowe import {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);
  107. 107. DEMO
  108. 108. Co dalej?
  109. 109. Offline mode
  110. 110. Generowanie PDF-ów let 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.') }); }); });
  111. 111. Bezpieczne przechowywanie tokenów
  112. 112. 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)
  113. 113. 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:
  114. 114. Pytania?
  115. 115. tomasz@dziuda.com @dziudek http://dziudek.pl http://www.slideshare.net/dziudek Tomasz Dziuda

×