@@ -161,6 +161,9 @@ public function rewrite_rules() {
161161 'api/v1/timelines/(home|public) ' => 'api/v1/timelines/$matches[1] ' ,
162162 'api/v1/timelines/tag/([^/|$]+) ' => 'api/v1/timelines/tag/$matches[1] ' ,
163163 'api/v2/search ' => 'api/v1/search ' ,
164+ 'api/v1/tags/(.+) ' => 'api/v1/tags/$matches[1] ' ,
165+ 'api/v1/tags/([^/]+)/follow ' => 'api/v1/tags/$matches[1]/follow ' ,
166+ 'api/v1/tags/([^/]+)/unfollow ' => 'api/v1/tags/$matches[1]/unfollow ' ,
164167 );
165168
166169 foreach ( $ generic as $ rule ) {
@@ -254,7 +257,7 @@ public function add_rest_routes() {
254257 'api/v1/followed_tags ' ,
255258 array (
256259 'methods ' => 'GET ' ,
257- 'callback ' => ' __return_empty_array ' ,
260+ 'callback ' => array ( $ this , ' api_followed_tags ' ) ,
258261 'permission_callback ' => array ( $ this , 'logged_in_permission ' ),
259262 )
260263 );
@@ -660,6 +663,36 @@ public function add_rest_routes() {
660663 'permission_callback ' => array ( $ this , 'logged_in_permission ' ),
661664 )
662665 );
666+
667+ register_rest_route (
668+ self ::PREFIX ,
669+ 'api/v1/tags/(?P<id>[^/]+) ' ,
670+ array (
671+ 'methods ' => array ( 'GET ' , 'OPTIONS ' ),
672+ 'callback ' => array ( $ this , 'api_tags ' ),
673+ 'permission_callback ' => array ( $ this , 'logged_in_permission ' ),
674+ )
675+ );
676+
677+ register_rest_route (
678+ self ::PREFIX ,
679+ 'api/v1/tags/(?P<id>[^/]+)/follow ' ,
680+ array (
681+ 'methods ' => array ( 'POST ' , 'OPTIONS ' ),
682+ 'callback ' => array ( $ this , 'api_tags_follow ' ),
683+ 'permission_callback ' => array ( $ this , 'logged_in_permission ' ),
684+ )
685+ );
686+
687+ register_rest_route (
688+ self ::PREFIX ,
689+ 'api/v1/tags/(?P<id>[^/]+)/unfollow ' ,
690+ array (
691+ 'methods ' => array ( 'POST ' , 'OPTIONS ' ),
692+ 'callback ' => array ( $ this , 'api_tags_unfollow ' ),
693+ 'permission_callback ' => array ( $ this , 'logged_in_permission ' ),
694+ )
695+ );
663696 }
664697
665698 public function query_vars ( $ query_vars ) {
@@ -1520,6 +1553,10 @@ public function api_timelines( $request ) {
15201553 public function api_tag_timelines ( $ request ) {
15211554 $ args = $ this ->get_posts_query_args ( $ request );
15221555 $ args ['tag ' ] = $ request ->get_param ( 'hashtag ' );
1556+
1557+ $ ppp_param = $ request ->get_param ( 'limit ' );
1558+ if ( $ ppp_param != null ) { $ args ['posts_per_page ' ] = $ ppp_param ; }
1559+
15231560 $ args = apply_filters ( 'mastodon_api_timelines_args ' , $ args , $ request );
15241561
15251562 return $ this ->get_posts ( $ args , $ request ->get_param ( 'min_id ' ), $ request ->get_param ( 'max_id ' ) );
@@ -1536,14 +1573,20 @@ public function api_search( $request ) {
15361573 $ ret = array (
15371574 'accounts ' => array (),
15381575 'statuses ' => array (),
1576+ 'hashtags ' => array (),
15391577 );
1578+ $ search_query = trim ( $ request ->get_param ( 'q ' ) );
1579+ // Don't allow empty search queries.
1580+ if ( $ search_query == '' ) {
1581+ return $ ret ;
1582+ }
15401583 if ( ! $ type || 'accounts ' === $ type ) {
1541- if ( preg_match ( '/^@? ' . self ::ACTIVITYPUB_USERNAME_REGEXP . '$/i ' , $ request -> get_param ( ' q ' ) ) && ! $ request ->get_param ( 'offset ' ) ) {
1542- $ ret ['accounts ' ][] = $ this ->get_friend_account_data ( $ request -> get_param ( ' q ' ) , array (), true );
1584+ if ( preg_match ( '/^@? ' . self ::ACTIVITYPUB_USERNAME_REGEXP . '$/i ' , $ search_query ) && ! $ request ->get_param ( 'offset ' ) ) {
1585+ $ ret ['accounts ' ][] = $ this ->get_friend_account_data ( $ search_query , array (), true );
15431586 }
15441587 $ query = new \WP_User_Query (
15451588 array (
1546- 'search ' => '* ' . $ request -> get_param ( ' q ' ) . '* ' ,
1589+ 'search ' => '* ' . $ search_query . '* ' ,
15471590 'search_columns ' => array (
15481591 'user_login ' ,
15491592 'user_nicename ' ,
@@ -1566,10 +1609,10 @@ public function api_search( $request ) {
15661609 return array ();
15671610 }
15681611 $ args = apply_filters ( 'mastodon_api_timelines_args ' , $ args , $ request );
1569- $ valid_url = wp_parse_url ( $ request -> get_param ( ' q ' ) );
1612+ $ valid_url = wp_parse_url ( $ search_query );
15701613 if ( $ valid_url && isset ( $ valid_url ['host ' ] ) ) {
15711614 if ( ! $ request ->get_param ( 'offset ' ) ) {
1572- $ url = $ request -> get_param ( ' q ' ) ;
1615+ $ url = $ search_query ;
15731616 $ json = $ this ->get_json ( $ url , crc32 ( $ url ) );
15741617 if ( ! is_wp_error ( $ json ) && isset ( $ json ['id ' ], $ json ['attributedTo ' ] ) ) {
15751618 $ user_id = $ this ->get_acct ( $ json ['attributedTo ' ] );
@@ -1583,13 +1626,39 @@ public function api_search( $request ) {
15831626 );
15841627 }
15851628 }
1586- } elseif ( is_user_logged_in () ) {
1587- $ args ['s ' ] = $ request ->get_param ( 'q ' );
1588- $ args ['offset ' ] = $ request ->get_param ( 'offset ' );
1589- $ args ['posts_per_page ' ] = $ request ->get_param ( 'limit ' );
1629+ } elseif ( is_user_logged_in () || $ this ->oauth ->get_token () ) {
1630+ $ args ['s ' ] = $ search_query ;
1631+
1632+ $ offset_param = $ request ->get_param ( 'offset ' );
1633+ if ( $ offset_param != null ) { $ args ['offset ' ] = $ offset_param ; }
1634+
1635+ $ ppp_param = $ request ->get_param ( 'limit ' );
1636+ if ( $ ppp_param != null ) { $ args ['posts_per_page ' ] = $ ppp_param ; }
1637+
15901638 $ ret ['statuses ' ] = array_merge ( $ ret ['statuses ' ], $ this ->get_posts ( $ args ) );
15911639 }
15921640 }
1641+ if ( ! $ type || 'hashtags ' === $ type ) {
1642+ $ token = $ this ->oauth ->get_token ();
1643+ $ user_id = $ token ['user_id ' ];
1644+
1645+ $ categories = $ this ->get_categories ();
1646+ $ post_data ['post_category ' ] = array ();
1647+ foreach ( $ categories as $ category ) {
1648+ if ( strcasecmp ( $ search_query , $ category ->name ) == 0 ) {
1649+ $ ret ['hashtags ' ][] = $ this ->generate_hashtag_array ( $ category , array (), $ this ->check_if_hashtag_followed ( $ user_id , $ category ->name ) );
1650+ }
1651+ }
1652+ $ tags = $ this ->get_tags ();
1653+ $ post_data ['tags_input ' ] = array ();
1654+ foreach ( $ tags as $ tag ) {
1655+ if ( strcasecmp ( $ search_query , $ tag ->name ) == 0 ) {
1656+ $ ret ['hashtags ' ][] = $ this ->generate_hashtag_array ( $ tag , array (), $ this ->check_if_hashtag_followed ( $ user_id , $ tag ->name ) );
1657+ }
1658+ }
1659+
1660+ }
1661+
15931662 return $ ret ;
15941663 }
15951664
@@ -2867,4 +2936,138 @@ public function api_instance_v2() {
28672936
28682937 return apply_filters ( 'mastodon_api_instance_v2 ' , $ ret );
28692938 }
2939+
2940+ public function api_tags ( $ request ) {
2941+ $ token = $ this ->oauth ->get_token ();
2942+ $ user_id = $ token ['user_id ' ];
2943+ $ hashtag = $ request ->get_param ( 'id ' );
2944+ $ followed = $ this ->check_if_hashtag_followed ( $ user_id , $ hashtag );
2945+
2946+ $ term = $ this ->find_hashtag_term ( $ hashtag );
2947+ return $ this ->generate_hashtag_array ( $ term , array (), $ followed );
2948+ }
2949+
2950+ public function api_tags_follow ( $ request ) {
2951+ $ token = $ this ->oauth ->get_token ();
2952+ $ user_id = $ token ['user_id ' ];
2953+
2954+ $ tags_followed = get_user_meta ( $ user_id , 'enable-mastodon-apps-tags-followed ' , true );
2955+
2956+ if ( $ tags_followed === false ) {
2957+ $ tags_followed = array ();
2958+ } else {
2959+ $ tags_followed = unserialize ( $ tags_followed );
2960+ }
2961+
2962+ $ hashtag = $ request ->get_param ( 'id ' );
2963+ $ term = $ this ->find_hashtag_term ( $ hashtag );
2964+
2965+ $ tags_followed [$ hashtag ] = true ;
2966+
2967+ update_user_meta ( $ user_id , 'enable-mastodon-apps-tags-followed ' , serialize ( $ tags_followed ) );
2968+
2969+ if ( $ term === null ) {
2970+ return $ this ->generate_hashtag_array ( '' );
2971+ }
2972+
2973+ return $ this ->generate_hashtag_array ( $ term , array (), true );
2974+ }
2975+
2976+ public function api_tags_unfollow ( $ request ) {
2977+ $ token = $ this ->oauth ->get_token ();
2978+ $ user_id = $ token ['user_id ' ];
2979+
2980+ $ tags_followed = get_user_meta ( $ user_id , 'enable-mastodon-apps-tags-followed ' , true );
2981+
2982+ if ( $ tags_followed === false ) {
2983+ $ tags_followed = array ();
2984+ } else {
2985+ $ tags_followed = unserialize ( $ tags_followed );
2986+ }
2987+
2988+ $ hashtag = $ request ->get_param ( 'id ' );
2989+ $ term = $ this ->find_hashtag_term ( $ hashtag );
2990+
2991+ unset( $ tags_followed [$ hashtag ] );
2992+
2993+ update_user_meta ( $ user_id , 'enable-mastodon-apps-tags-followed ' , serialize ( $ tags_followed ) );
2994+
2995+ if ( $ term === null ) {
2996+ return $ this ->generate_hashtag_array ( '' );
2997+ }
2998+
2999+ return $ this ->generate_hashtag_array ( $ term , array () );
3000+ }
3001+
3002+ public function api_followed_tags ( $ request ) {
3003+ $ token = $ this ->oauth ->get_token ();
3004+ $ user_id = $ token ['user_id ' ];
3005+
3006+ $ tags_followed = get_user_meta ( $ user_id , 'enable-mastodon-apps-tags-followed ' , true );
3007+
3008+ if ( $ tags_followed === false ) {
3009+ $ tags_followed = array ();
3010+ } else {
3011+ $ tags_followed = unserialize ( $ tags_followed );
3012+ }
3013+
3014+ $ ret = array ();
3015+ foreach ( $ tags_followed as $ key => $ value ) {
3016+ $ term = $ this ->find_hashtag_term ( $ key );
3017+ $ ret [] = $ this ->generate_hashtag_array ( $ term , array (), true );
3018+ }
3019+
3020+ return $ ret ;
3021+ }
3022+
3023+ private function generate_hashtag_array ( $ term , $ history = array (), $ following = false ) {
3024+ $ ret = array ( 'name ' => $ term ->name , 'url ' => get_term_link ( $ term ), 'history ' => $ history );
3025+ if ( $ following ) {
3026+ $ ret ['following ' ] = true ;
3027+ }
3028+ return $ ret ;
3029+ }
3030+
3031+ private function get_categories () {
3032+ return get_categories ( array ( 'orderby ' => 'name ' , 'hide_empty ' => false ) );
3033+ }
3034+
3035+ private function get_tags () {
3036+ return get_tags ( array ( 'orderby ' => 'name ' , 'hide_empty ' => false ) );
3037+ }
3038+
3039+ private function find_hashtag_term ( $ hashtag ) {
3040+ $ tags = $ this ->get_tags ();
3041+ $ post_data ['tags_input ' ] = array ();
3042+ foreach ( $ tags as $ tag ) {
3043+ if ( strcmp ( $ hashtag , $ tag ->name ) == 0 ) {
3044+ return $ tag ;
3045+ }
3046+ }
3047+ $ categories = $ this ->get_categories ();
3048+ $ post_data ['post_category ' ] = array ();
3049+ foreach ( $ categories as $ category ) {
3050+ if ( strcmp ( $ hashtag , $ category ->name ) == 0 ) {
3051+ return $ category ;
3052+ }
3053+ }
3054+ return null ;
3055+ }
3056+
3057+ private function check_if_hashtag_followed ( $ user_id , $ hashtag ) {
3058+ $ tags_followed = get_user_meta ( $ user_id , 'enable-mastodon-apps-tags-followed ' , true );
3059+
3060+ if ( $ tags_followed === false ) {
3061+ $ tags_followed = array ();
3062+ } else {
3063+ $ tags_followed = unserialize ( $ tags_followed );
3064+ }
3065+
3066+ if ( array_key_exists ( $ hashtag , $ tags_followed ) ) {
3067+ return true ;
3068+ }
3069+
3070+ return false ;
3071+ }
3072+
28703073}
0 commit comments