Simple Read-Only JSON API in WordPress

In need of a reliable long term WordPress JSON API, I ended up with this class.

Update: With the recent addition of the REST API in WordPress core, this class is probably less necessary.

[pastacode lang=”php” manual=”%3C%3Fphp%0A%2F**%0A%20*%20Class%20Simple_Json_Api%0A%20*%2F%0Aclass%20Simple_Json_Api%20%7B%0A%09%2F**%0A%09%20*%20The%20top%20level%20argument%20for%20the%20endpoint.%0A%09%20*%20ex%20http%3A%2F%2Fexample.com%2Fmyjson%2Fpost%2F1%0A%09%20*%0A%09%20*%20%40var%20string%0A%09%20*%2F%0A%09public%20%24endpoint_base%20%3D%20’myjson’%3B%0A%09%2F**%0A%09%20*%20Only%20provide%20json%20data%20for%20the%20post_types%20in%20this%20array.%0A%09%20*%0A%09%20*%20%40var%20array%0A%09%20*%2F%0A%09public%20%24allowed_post_types%20%3D%20array(%20’post’%20)%3B%0A%09%2F**%0A%09%20*%20Default%20WP_Query%20arguments%20for%20retrieving%20posts.%0A%09%20*%20Here%20you%20can%20limit%20the%20number%20of%20items%20returned%2C%20or%20change%20the%20order%0A%09%20*%20of%20items%20returned%2C%20etc.%0A%09%20*%0A%09%20*%20%40var%20array%0A%09%20*%2F%0A%09public%20%24default_query_arguments%20%3D%20array(%0A%09%09’posts_per_page’%20%3D%3E%2010%2C%0A%09%09’post_status’%20%3D%3E%20array(%20’publish’%20)%2C%0A%09%09’orderby’%20%3D%3E%20’date’%2C%0A%09%09’order’%20%3D%3E%20’ASC’%2C%0A%09%09’ignore_sticky_posts’%20%3D%3E%20true%0A%09)%3B%0A%09%2F**%0A%09%20*%20Create%20an%20array%20of%20data%20for%20a%20single%20post%20that%20will%20be%20part%0A%09%20*%20of%20the%20json%20response.%0A%09%20*%0A%09%20*%20%40param%20%24post%0A%09%20*%2F%0A%09static%20public%20function%20make_json_data(%20%24post%20)%7B%0A%09%09%2F%2F%20featured%20image%20urls%0A%09%09%24image_id%20%3D%20get_post_thumbnail_id(%20%24post-%3EID%20)%3B%0A%09%09%24image_full%20%20%3D%20wp_get_attachment_image_src(%20%24image_id%2C%20’full’%20)%3B%0A%09%09%24image_thumb%20%3D%20wp_get_attachment_image_src(%20%24image_id%2C%20’thumbnail’%20)%3B%0A%09%09%24item%20%3D%20array(%0A%09%09%09%2F%2F%20The%20global%20%24post%20object%20is%20set%2C%20so%20we%20can%20use%20template%20tags.%0A%09%09%09%2F%2F%20Additionally%2C%20we%20have%20the%20object%2C%20so%20we%20could%20get%20raw%20data.%0A%09%09%09’title’%20%3D%3E%20get_the_title()%2C%0A%09%09%09’title_raw’%20%3D%3E%20%24post-%3Epost_title%2C%0A%09%09%09’content’%20%3D%3E%20get_the_content()%2C%0A%09%09%09’content_raw’%20%3D%3E%20%24post-%3Epost_content%2C%0A%09%09%09’date’%20%3D%3E%20get_the_date()%2C%0A%09%09%09’date_raw’%20%3D%3E%20%24post-%3Epost_date%2C%0A%09%09%09%2F%2F%20meta%20values%0A%09%09%09’my_meta_value’%20%3D%3E%20get_post_meta(%20%24post-%3EID%2C%20’my_meta_value’%2C%20TRUE%20)%2C%0A%09%09%09%2F%2F%20all%20meta%20values%20(%20not%20recommended%20unless%20you’re%20sure%20you%20want%20to%20do%20this%20)%0A%09%09%09%2F%2F’meta’%20%3D%3E%20get_post_meta(%20%24post-%3EID%20)%2C%0A%09%09%09%2F%2F%20default%20image%20values%0A%09%09%09’image_id’%20%3D%3E%20!empty(%20%24image_id%20)%20%3F%20%24image_id%20%3A%20false%2C%0A%09%09%09’image_full’%20%3D%3E%20!empty(%20%24image_full%5B0%5D%20)%20%3F%20%24image_full%5B0%5D%20%3A%20false%2C%0A%09%09%09’image_thumb’%20%3D%3E%20!empty(%20%24image_thumb%5B0%5D%20)%20%3F%20%24image_thumb%5B0%5D%20%3A%20false%2C%0A%09%09%09%2F%2F%20taxonomy%20data%0A%09%09%09’categories’%20%3D%3E%20get_the_terms(%20%24post-%3EID%2C%20’category’%20)%2C%0A%09%09%09’tags’%20%3D%3E%20get_the_terms(%20%24post-%3EID%2C%20’post_tag’%20)%2C%0A%09%09)%3B%0A%09%09%2F%2F%20OPTIONAL%3A%0A%09%09%2F%2F%20Depending%20on%20your%20plugin%20organizational%20structure%2C%20you%20may%20want%20each%0A%09%09%2F%2F%20post_type%20to%20be%20able%20to%20control%20its%20own%20json%20data.%20%20In%20that%20case%2C%20you%20%0A%09%09%2F%2F%20could%20use%20a%20dynamic%20hook%20like%20this%20to%20provide%20that%20flexibility.%0A%09%09%2F%2F%20return%20apply_filters(%20%22myjson_api_%7B%24post-%3Epost_type%7D_data%22%2C%20%24item%2C%20%24post%20)%3B%0A%09%09return%20%24item%3B%0A%09%7D%0A%09%2F**%0A%09%20*%20Hook%20the%20plugin%20into%20WordPress%0A%09%20*%2F%0A%09static%20public%20function%20register()%7B%0A%09%09%24plugin%20%3D%20new%20self()%3B%0A%09%09add_action(%20’init’%2C%20array(%20%24plugin%2C%20’add_endpoint’%20)%20)%3B%0A%09%09add_action(%20’template_redirect’%2C%20array(%20%24plugin%2C%20’handle_endpoint’%20)%20)%3B%0A%09%7D%0A%09%2F**%0A%09%20*%20Create%20our%20json%20endpoint%20by%20adding%20new%20rewrite%20rules%20to%20WordPress%0A%09%20*%2F%0A%09function%20add_endpoint()%7B%0A%09%09%24post_type_tag%20%3D%20%24this-%3Eendpoint_base%20.%20’_type’%3B%0A%09%09%24post_id_tag%20%20%20%3D%20%24this-%3Eendpoint_base%20.%20’_id’%3B%0A%09%09%2F%2F%20Add%20new%20rewrite%20tags%20to%20WP%20for%20our%20endpoint’s%20post_type%0A%09%09%2F%2F%20and%20post_id%20arguments%0A%09%09add_rewrite_tag(%20%22%25%7B%24post_type_tag%7D%25%22%2C%20′(%5B%5E%26%5D%2B)’%20)%3B%0A%09%09add_rewrite_tag(%20%22%25%7B%24post_id_tag%7D%25%22%2C%20′(%5B0-9%5D%2B)’%20)%3B%0A%09%09%2F%2F%20Add%20the%20rules%20that%20look%20for%20our%20rewrite%20tags%20in%20the%20route%20query.%0A%09%09%2F%2F%20Most%20specific%20rule%20first%2C%20then%20fallback%20to%20the%20general%20rule%0A%09%09%2F%2F%20specific%20rule%20finds%20a%20single%20post%0A%09%09%2F%2F%20http%3A%2F%2Fexample.com%2Fmyjson%2Fpost%2F1%0A%09%09add_rewrite_rule(%0A%09%09%09%24this-%3Eendpoint_base%20.%20’%2F(%5B%5E%26%5D%2B)%2F(%5B0-9%5D%2B)%2F%3F’%2C%0A%09%09%09’index.php%3F’.%24post_type_tag.’%3D%24matches%5B1%5D%26′.%24post_id_tag.’%3D%24matches%5B2%5D’%2C%0A%09%09%09’top’%20)%3B%0A%09%09%2F%2F%20general%20rule%20finds%20%22all%22%20(post_per_page)%20of%20a%20given%20post_type%0A%09%09%2F%2F%20http%3A%2F%2Fexample.com%2Fmyjson%2Fpost%0A%09%09add_rewrite_rule(%0A%09%09%09%24this-%3Eendpoint_base%20.%20’%2F(%5B%5E%26%5D%2B)%2F%3F’%2C%0A%09%09%09’index.php%3F’.%24post_type_tag.’%3D%24matches%5B1%5D’%2C%0A%09%09%09’top’%20)%3B%0A%09%7D%0A%09%2F**%0A%09%20*%20Handle%20the%20request%20of%20an%20endpoint%0A%09%20*%2F%0A%09function%20handle_endpoint()%7B%0A%09%09global%20%24wp_query%3B%0A%09%09%2F%2F%20get%20the%20query%20args%20and%20sanitize%20them%20for%20confidence%0A%09%09%24type%20%3D%20sanitize_text_field(%20%24wp_query-%3Eget(%20%24this-%3Eendpoint_base%20.%20’_type’%20)%20)%3B%0A%09%09%24id%20%20%20%3D%20intval(%20%24wp_query-%3Eget(%20%24this-%3Eendpoint_base%20.%20’_id’%20)%20)%3B%0A%09%09%0A%09%09%2F%2F%20only%20allowed%20post_types%0A%09%09if%20(%20!%20in_array(%20%24type%2C%20%24this-%3Eallowed_post_types%20)%20)%20%7B%0A%09%09%09return%3B%0A%09%09%7D%0A%09%09%2F%2F%20the%20post_type%20of%20the%20given%20id%20must%20match%20the%20requested%20post_type%0A%09%09if%20(%20%24id%20%26%26%20get_post_type(%20%24id%20)%20!%3D%20%24type%20)%20%7B%0A%09%09%09return%3B%0A%09%09%7D%0A%09%09%0A%09%09%2F%2F%20start%20with%20our%20default%20query%20arguments%0A%09%09%24args%20%3D%20%24this-%3Edefault_query_arguments%3B%0A%09%09%2F%2F%20add%20the%20post_type%0A%09%09%24args%5B’post_type’%5D%20%3D%20array(%20%24type%20)%3B%0A%09%09%2F%2F%20add%20the%20post%20ID%20if%20specified%0A%09%09if%20(%20%24id%20)%20%7B%0A%09%09%09%24args%5B’post__in’%5D%20%3D%20array(%20%24id%20)%3B%0A%09%09%7D%0A%09%09%24query%20%3D%20new%20WP_Query(%20%24args%20)%3B%0A%09%09%24data%20%3D%20array()%3B%0A%09%09%2F%2F%20loop%20through%20the%20posts%20and%20build%20our%20endpoint%20data%20arrays%0A%09%09if%20(%20%24query-%3Ehave_posts()%20)%20%7B%0A%09%09%09while%20(%20%24query-%3Ehave_posts()%20)%20%7B%0A%09%09%09%09%24query-%3Ethe_post()%3B%0A%09%09%09%09global%20%24post%3B%0A%09%09%09%09%24data%5B%5D%20%3D%20self%3A%3Amake_json_data(%20%24post%20)%3B%0A%09%09%09%7D%0A%09%09%09wp_reset_query()%3B%0A%09%09%7D%0A%09%09%2F%2F%20data%20is%20built.%20print%20as%20json%20and%20stop%0A%09%09wp_send_json(%20%24data%20)%3B%20exit%3B%0A%09%7D%0A%7D%0A%2F%2F%20huzzah!%0ASimple_Json_Api%3A%3Aregister()%3B” message=”” highlight=”” provider=”manual”/]

0 Thoughts

Discussion

Leave a Reply

Your email address will not be published. Required fields are marked *