SlideShare a Scribd company logo
1 of 35
Download to read offline
Django
+ WordPress.com REST API =
PROFIT
Jeff Sternberg, VP Tech
Observer Media
jsternberg@observer.com
https://www.linkedin.com/in/jeffsternberg
@sternb0t
About me
- Lead engineer @Observer < 1 year
- NYC fintech startups ~ 2 years
- S&P Capital IQ ~ 10 years
- Once and future data scientist
- Python brings me joy, SQL makes me happy
- First code-for-pay: AppleScript
About Observer
- Founded in 1987
- We publish an actual
printed newspaper, the
weekly New York Observer
- Observer.com
- PolitickerNJ.com
- CommercialObserver.com
Commercial Observer
- Commercial real estate
- Leasing, sales, financing, construction,
infrastructure, industry players, features
- Weekly print edition
- Strong since inception 5 years ago
- Digital edition
- Needed some love
Before..
After!
Setting the CO Scene
- Small in-house editorial team
- Handful of contributors (industry experts)
- WordPress codebase, launched years ago*
- Not modified much since launch
- Hosted on WordPress.com VIP
*I don’t actually know when it was launched
WordWhat?
Though it powers 25%
of the internet, I hadn’t
ever built anything with
WordPress.
I didn’t even know PHP.
WordPress is actually pretty good
- Great WYSIWYG post editor
- Easy for editors and writers to learn
- Decent media library
- Handles most publishing use cases
- Lots of useful plugins
- Large developer community
Except...
- Rigid data model: everything’s a Post
- Not MVC
- Plugin spaghetti
- Most WP sites are hobbyist/small blogs;
enterprise WP community is fairly small
- Locked-down VIP hosting optimized for
high traffic sites like observer.com
Let’s build this in Django.
Ok, maybe just the front end.
Django / WordPress integration
Option 1: Django connects to WordPress db
WordPress content db
(mysql)
WordPress web app (php) Django web app (python)
HTTP/HTML HTTP/HTML
TCP (data)
Django / WordPress integration
Option 1: Django connects to WordPress db
- sunlightlabs/django-wordpress
- agiliq/django-wordpress
- Or, roll your own models
- WordPress only has ~12 tables
Django / WordPress integration
Option 2: Coupled REST API
WordPress content db
mysql
WordPress web app (php) Django web app (python)
HTTP/HTML HTTP/HTML
HTTP/REST
Django / WordPress integration
Option 2: Coupled REST API
- WordPress.com REST API
- https://developer.wordpress.com/docs/api/
- WordPress.org: use WP REST API
- http://v2.wp-api.org/
Django / WordPress integration
Option 3: Decoupled REST API
WordPress content db
mysql
WordPress web app (php) Django web app (python)
HTTP/HTML HTTP/HTML
HTTP/REST
Django db
Django / WordPress integration
Option 3: Decoupled REST API
- Same WP REST APIs
- Django has its own copy of the content db
- Sync content with cron + webhooks
Shared db vs. REST API
Shared db
- Faster data access
- Django should be
in the same
network as WP
- Read/write?
REST API
- Django can use
separate hosting /
network
- Higher latency
- Data serialization /
deserialization
Coupled vs. Decoupled REST API
Coupled
- Only 1 copy of the
content db
- Site uptime
depends on both
Django and WP
Decoupled
- Can easily alter /
extend db schema
- Data sync scripts
can be tricky
- Hosting flexibility
For WordPress.org sites
For WordPress.com sites
WordPress.com REST API
- Sane data model
- /v1.1/sites/$site_id/posts
- /v1.1/sites/$site_id/tags
- etc.
- OAuth2 for private data (e.g. draft posts)
- Handy dev console
- Good documentation
- Some gotchas
Gotchas: WordPress.com REST API
Whitelist custom post types in theme code:
/** Allow additional post types in wp.com REST API */
function obs_rest_api_post_types( $allowed_post_types ) {
$allowed_post_types[] = 'guest-author';
$allowed_post_types[] = 'attachment';
$allowed_post_types[] = 'sponsored-post';
return $allowed_post_types;
}
add_filter( 'rest_api_allowed_post_types',
'obs_rest_api_post_types' );
Gotchas: WordPress.com REST API
- Custom taxonomies are not supported:
the only post terms you can fetch are
tags and categories
- So we can use post meta as a
workaround...
/* Save coauthors slugs in meta */
function obs_save_coauthor_tax_as_meta( $post_id ) {
$authors = get_coauthors( $post_id );
$author_str = json_encode( array_map(
function( $a ) { return 'cap-' . $a; },
wp_list_pluck( $authors, 'user_nicename' ) ) );
if ( $author_str ) {
update_post_meta( $post_id, 'nyo-cap-slug',
$author_str );
} else {
delete_post_meta( $post_id, 'nyo-cap-slug' );
}
}
add_action( 'save_post', 'obs_save_coauthor_tax_as_meta' );
Decoupled data syncing
- Django command (cron)
- Webhook
$ python manage.py load_wp_api
$ curl -X POST --data "ID=281878" http://co/api/story
import requests
from django.conf import settings
def load_posts(site_id, post_type):
api_url = "https://public-api.wordpress.com/rest/v1.1/" 
"sites/{}/posts".format(site_id)
headers = {"Authorization":
"Bearer {}".format(settings.WP_API_TOKEN)}
params = {"number": 100, "type": post_type}
page = 1
Django command (cron)
def load_posts(site_id, post_type):
# ...
# set modified_after to "continue where we left off"
latest = Post.objects.filter(post_type=post_type)
.order_by("-modified")
.first()
if latest:
params["modified_after"] = latest.modified.isoformat()
# get first page
response = requests.get(api_url, params=params,
headers=headers)
Django command (cron) continued
def load_posts(site_id, post_type):
# ...
while response.ok and response.text:
api_json = response.json()
api_posts = api_json.get("posts")
for api_post in api_posts:
load_wp_post(site_id, api_post) # helper function
next_page_handle = api_json.get("meta", {})
.get("next_page")
if next_page_handle:
params["page_handle"] = next_page_handle
else:
break # no more pages left
response = requests.get(api_url, params=params,
headers=headers)
from rest_framework.views import APIView
from rest_framework.response import Response
class LoadAPIStoryView(APIView):
def post(self, request):
try:
wp_id = int(request.POST["ID"])
except:
raise Http404("Post does not exist")
load_story.after_response(request, wp_id)
return Response({"status":
"loading wp_id: {}".format(wp_id)})
Webhook
import after_response
from django.conf import settings
from wordpress.wp_api import load_wp_api_one_post
@after_response.enable
def load_story(request, wp_post_id):
# let WP REST API catch up
time.sleep(1)
try:
load_wp_api_one_post(settings.WP_SITE_ID, wp_post_id)
except:
logger.exception("Fail! wp_post_id=%s", wp_post_id)
Webhook continued
django-wordpress-rest
This code is here:
https://github.com/observermedia/django-wordpress-rest
Contact me to contribute if interested!
(Or if you find bugs…)
We’re hiring

More Related Content

Recently uploaded

Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfAlex Barbosa Coqueiro
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Mark Simos
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024Stephanie Beckett
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostZilliz
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 

Recently uploaded (20)

Unraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdfUnraveling Multimodality with Large Language Models.pdf
Unraveling Multimodality with Large Language Models.pdf
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
Tampa BSides - Chef's Tour of Microsoft Security Adoption Framework (SAF)
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 
What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024What's New in Teams Calling, Meetings and Devices March 2024
What's New in Teams Calling, Meetings and Devices March 2024
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage CostLeverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
Leverage Zilliz Serverless - Up to 50X Saving for Your Vector Storage Cost
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 

Featured

AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 

Featured (20)

AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 

Django + WordPress.com REST API = Profit

  • 1. Django + WordPress.com REST API = PROFIT Jeff Sternberg, VP Tech Observer Media jsternberg@observer.com https://www.linkedin.com/in/jeffsternberg @sternb0t
  • 2. About me - Lead engineer @Observer < 1 year - NYC fintech startups ~ 2 years - S&P Capital IQ ~ 10 years - Once and future data scientist - Python brings me joy, SQL makes me happy - First code-for-pay: AppleScript
  • 3. About Observer - Founded in 1987 - We publish an actual printed newspaper, the weekly New York Observer - Observer.com - PolitickerNJ.com - CommercialObserver.com
  • 4. Commercial Observer - Commercial real estate - Leasing, sales, financing, construction, infrastructure, industry players, features - Weekly print edition - Strong since inception 5 years ago - Digital edition - Needed some love
  • 7. Setting the CO Scene - Small in-house editorial team - Handful of contributors (industry experts) - WordPress codebase, launched years ago* - Not modified much since launch - Hosted on WordPress.com VIP *I don’t actually know when it was launched
  • 8. WordWhat? Though it powers 25% of the internet, I hadn’t ever built anything with WordPress. I didn’t even know PHP.
  • 9. WordPress is actually pretty good - Great WYSIWYG post editor - Easy for editors and writers to learn - Decent media library - Handles most publishing use cases - Lots of useful plugins - Large developer community
  • 10. Except... - Rigid data model: everything’s a Post - Not MVC - Plugin spaghetti - Most WP sites are hobbyist/small blogs; enterprise WP community is fairly small - Locked-down VIP hosting optimized for high traffic sites like observer.com
  • 11. Let’s build this in Django.
  • 12. Ok, maybe just the front end.
  • 13. Django / WordPress integration Option 1: Django connects to WordPress db WordPress content db (mysql) WordPress web app (php) Django web app (python) HTTP/HTML HTTP/HTML TCP (data)
  • 14. Django / WordPress integration Option 1: Django connects to WordPress db - sunlightlabs/django-wordpress - agiliq/django-wordpress - Or, roll your own models - WordPress only has ~12 tables
  • 15. Django / WordPress integration Option 2: Coupled REST API WordPress content db mysql WordPress web app (php) Django web app (python) HTTP/HTML HTTP/HTML HTTP/REST
  • 16. Django / WordPress integration Option 2: Coupled REST API - WordPress.com REST API - https://developer.wordpress.com/docs/api/ - WordPress.org: use WP REST API - http://v2.wp-api.org/
  • 17. Django / WordPress integration Option 3: Decoupled REST API WordPress content db mysql WordPress web app (php) Django web app (python) HTTP/HTML HTTP/HTML HTTP/REST Django db
  • 18. Django / WordPress integration Option 3: Decoupled REST API - Same WP REST APIs - Django has its own copy of the content db - Sync content with cron + webhooks
  • 19. Shared db vs. REST API Shared db - Faster data access - Django should be in the same network as WP - Read/write? REST API - Django can use separate hosting / network - Higher latency - Data serialization / deserialization
  • 20. Coupled vs. Decoupled REST API Coupled - Only 1 copy of the content db - Site uptime depends on both Django and WP Decoupled - Can easily alter / extend db schema - Data sync scripts can be tricky - Hosting flexibility
  • 21. For WordPress.org sites For WordPress.com sites
  • 22. WordPress.com REST API - Sane data model - /v1.1/sites/$site_id/posts - /v1.1/sites/$site_id/tags - etc. - OAuth2 for private data (e.g. draft posts) - Handy dev console - Good documentation - Some gotchas
  • 23.
  • 24.
  • 25. Gotchas: WordPress.com REST API Whitelist custom post types in theme code: /** Allow additional post types in wp.com REST API */ function obs_rest_api_post_types( $allowed_post_types ) { $allowed_post_types[] = 'guest-author'; $allowed_post_types[] = 'attachment'; $allowed_post_types[] = 'sponsored-post'; return $allowed_post_types; } add_filter( 'rest_api_allowed_post_types', 'obs_rest_api_post_types' );
  • 26. Gotchas: WordPress.com REST API - Custom taxonomies are not supported: the only post terms you can fetch are tags and categories - So we can use post meta as a workaround...
  • 27. /* Save coauthors slugs in meta */ function obs_save_coauthor_tax_as_meta( $post_id ) { $authors = get_coauthors( $post_id ); $author_str = json_encode( array_map( function( $a ) { return 'cap-' . $a; }, wp_list_pluck( $authors, 'user_nicename' ) ) ); if ( $author_str ) { update_post_meta( $post_id, 'nyo-cap-slug', $author_str ); } else { delete_post_meta( $post_id, 'nyo-cap-slug' ); } } add_action( 'save_post', 'obs_save_coauthor_tax_as_meta' );
  • 28. Decoupled data syncing - Django command (cron) - Webhook $ python manage.py load_wp_api $ curl -X POST --data "ID=281878" http://co/api/story
  • 29. import requests from django.conf import settings def load_posts(site_id, post_type): api_url = "https://public-api.wordpress.com/rest/v1.1/" "sites/{}/posts".format(site_id) headers = {"Authorization": "Bearer {}".format(settings.WP_API_TOKEN)} params = {"number": 100, "type": post_type} page = 1 Django command (cron)
  • 30. def load_posts(site_id, post_type): # ... # set modified_after to "continue where we left off" latest = Post.objects.filter(post_type=post_type) .order_by("-modified") .first() if latest: params["modified_after"] = latest.modified.isoformat() # get first page response = requests.get(api_url, params=params, headers=headers) Django command (cron) continued
  • 31. def load_posts(site_id, post_type): # ... while response.ok and response.text: api_json = response.json() api_posts = api_json.get("posts") for api_post in api_posts: load_wp_post(site_id, api_post) # helper function next_page_handle = api_json.get("meta", {}) .get("next_page") if next_page_handle: params["page_handle"] = next_page_handle else: break # no more pages left response = requests.get(api_url, params=params, headers=headers)
  • 32. from rest_framework.views import APIView from rest_framework.response import Response class LoadAPIStoryView(APIView): def post(self, request): try: wp_id = int(request.POST["ID"]) except: raise Http404("Post does not exist") load_story.after_response(request, wp_id) return Response({"status": "loading wp_id: {}".format(wp_id)}) Webhook
  • 33. import after_response from django.conf import settings from wordpress.wp_api import load_wp_api_one_post @after_response.enable def load_story(request, wp_post_id): # let WP REST API catch up time.sleep(1) try: load_wp_api_one_post(settings.WP_SITE_ID, wp_post_id) except: logger.exception("Fail! wp_post_id=%s", wp_post_id) Webhook continued
  • 34. django-wordpress-rest This code is here: https://github.com/observermedia/django-wordpress-rest Contact me to contribute if interested! (Or if you find bugs…)