Flutter and WordPress: How to build a NewsApp

In the previous section, we have seen how we can use WordPress as the backend of the Flutter app. Flutter and WordPress can work together.

We can create, retrieve, update, and delete our posts in the WordPress web app. And, as an effect, that will reflect on the Flutter App.

For example, we had created a minimalist App which looks as follows.

Flutter WordPress challenge second example
Flutter WordPress challenge second example

From the WordPress database, it retrieves the titles and display them on our Flutter App.

However, we cannot just display the title only. On the contrary, we should display the posts, images also.

How to create a NewsApp in WordPress?

All we need a basic understanding of WordPress. That will help us to install a ready made theme that comes with demo content.

Therefore, it does not take much time to create a NewsApp in WordPress.

But to use that NewsApp as a backend for Flutter, we need a package first.

In our earlier sections, we have discussed how to use HTTP package. We will use the same package here.

As a result, in our model folder, we have a Post class.

import 'dart:convert';
import 'package:http/http.dart' as http;

/// fourth test to test latest post by category ID

class Post {
  String baseURLForAllPosts =
      'http://news.sanjibsinha.com/wp-json/wp/v2/posts?_embed';

  String latestPostsByCategoryID =
      'http://news.sanjibsinha.com/wp-json/wp/v2/latest-posts/';

  Future<List> getAllPosts() async {
    try {
      var response = await http.get(Uri.parse(baseURLForAllPosts));
      if (response.statusCode == 200) {
        return jsonDecode(response.body);
      } else {
        return Future.error('Server Error');
      }
    } catch (e) {
      throw '$e';
    }
  }

  Future<List> getPostsByCategoryID(int id) async {
    String latestPosts = '$latestPostsByCategoryID/$id';
    try {
      var response = await http.get(Uri.parse(latestPosts));
      if (response.statusCode == 200) {
        return jsonDecode(response.body);
      } else {
        return Future.error('Server Error');
      }
    } catch (e) {
      throw '$e';
    }
  }
}

Firstly, we will display all the posts on our home page of the Flutter App.

Flutter backend WordPress first
Flutter backend WordPress first page

Our home page displays all the posts. We can scroll down so we can view other posts also.

Flutter backend WordPress second
Flutter backend WordPress : scrolling down to the bottom

Each post comes with the title, featured image and the post. Although the post shows a few lines only.

Meanwhile, to read the full post, we can click any post on the home page. That will take us to the destination page.

Flutter backend WordPress third
Flutter backend WordPress : Post page

For instance, just like the home page, we can scroll down the single post to read the full post.

Flutter backend WordPress fourth
Flutter backend WordPress : Single post scroll

In addition, we can press the back button to get back to the home page again.

As we add the new post, that will reflect on our Flutter home page. How does it happen? Let’s see.

How Can I use flutter with WordPress?

Firstly, we have added the dependency in our “pubspec.yaml” file. Remember, we need the HTTP package to send the request and receive the response.

After that, based on that response, we retrieve the content. In other words, the HTTP package plays the most important role.

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  http: ^0.13.4
  google_fonts: ^2.3.1

On the other hand, the Google fonts package helps us to enhance the styling. For example we can use any fancy font, if we wish.

But, we should always use the fonts that are easy to read.

Secondly, in the home page we will use the Future Builder widget that has a property future which get all posts.

Besides, the builder property will return the ListView builder constructor that will display all the posts with title, image and content.

import 'package:flutter/material.dart';
import 'package:flutter_wordpress_challenge/model/happy_theme.dart';

import '../model/post.dart';
import 'post_detail.dart';

/// added content
/// adding the navigation

class FlutterWordPressHomePage extends StatefulWidget {
  const FlutterWordPressHomePage({Key? key, required this.title})
      : super(key: key);

  final String title;

  @override
  State<FlutterWordPressHomePage> createState() =>
      _FlutterWordPressHomePageState();
}

class _FlutterWordPressHomePageState extends State<FlutterWordPressHomePage> {
  @override
  void initState() {
    super.initState();
    Post().getAllPosts();
  }

  @override
  Widget build(BuildContext context) {
    Post posts = Post();
    return Scaffold(
      backgroundColor: HappyTheme.shrineErrorRed,
      appBar: AppBar(
        backgroundColor: HappyTheme.shrineBrown600,
        title: Text(
          widget.title,
          style: HappyTheme.appbarStyle,
        ),
      ),
      body: Center(
        child: Container(
          color: HappyTheme.shrinePink300,
          margin: const EdgeInsets.all(8.0),
          child: FutureBuilder<List>(
            future: posts.getAllPosts(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                if (snapshot.data!.isEmpty) {
                  return const Center(
                    child: Text('No Post available.'),
                  );
                }
                return ListView.builder(
                  itemCount: snapshot.data?.length,
                  itemBuilder: (context, index) {
                    return Card(
                      elevation: 10.0,
                      shadowColor: HappyTheme.shrineErrorRed,
                      child: ListTile(
                        title: Row(
                          children: [
                            Expanded(
                              child: Container(
                                padding: const EdgeInsets.all(8.0),
                                width: 150,
                                height: 150,
                                child: Image.network(snapshot.data![index]
                                        ['_embedded']['wp:featuredmedia'][0]
                                    ['source_url']),
                              ),
                            ),
                            Expanded(
                              child: Container(
                                padding: const EdgeInsets.all(10.0),
                                child: Text(
                                  snapshot.data![index]['title']['rendered'],
                                  style: HappyTheme.titleStyle,
                                ),
                              ),
                            ),
                          ],
                        ),
                        subtitle: Container(
                          padding: const EdgeInsets.all(10.0),
                          child: Text(
                            snapshot.data![index]['content']['rendered']
                                .toString()
                                .replaceAll('<p>', '')
                                .replaceAll('</p>', '')
                                .replaceAll('<strong>', '')
                                .replaceAll('</strong>', ''),
                            maxLines: 4,
                            overflow: TextOverflow.ellipsis,
                            style: HappyTheme.contentStyle,
                          ),
                        ),
                        onTap: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => PostDetail(
                                data: snapshot.data![index],
                              ),
                            ),
                          );
                        },
                      ),
                    );
                  },
                );
              } else if (snapshot.hasError) {
                return Center(
                  child: Text(snapshot.error.toString()),
                );
              } else {
                return const Center(
                  child: CircularProgressIndicator(),
                );
              }
            },
          ),
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Finally, we should be careful about getting the data in the right manner.

Why?

Because the data comes in a JSON format. Therefore, we have to extract the key to get the value.

Sending data to the single post page

We have discussed how to send data from one page to another page. In addition, we have the data as a single List of various maps and lists inside.

Above all, every post has the index associated with it.

import 'package:flutter/material.dart';
import 'package:flutter_wordpress_challenge/model/happy_theme.dart';

class PostDetail extends StatelessWidget {
  const PostDetail({
    Key? key,
    required this.data,
  }) : super(key: key);
  final Map<dynamic, dynamic> data;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Back Home'),
      ),
      body: ListView(
        children: [
          Container(
            margin: const EdgeInsets.all(10.0),
            child: Text(
              data['title']['rendered'],
              style: const TextStyle(
                fontSize: 40.0,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          const SizedBox(
            height: 10.0,
          ),
          Container(
            padding: const EdgeInsets.all(8.0),
            width: 450,
            height: 450,
            child: ClipOval(
              child: Image.network(
                data['_embedded']['wp:featuredmedia'][0]['source_url'],
                fit: BoxFit.cover,
              ),
            ),
          ),
          Container(
            padding: const EdgeInsets.all(10.0),
            child: Text(
              data['content']['rendered']
                  .toString()
                  .replaceAll('<p>', '')
                  .replaceAll('</p>', '')
                  .replaceAll('<strong>', '')
                  .replaceAll('</strong>', ''),
              style: HappyTheme.postContentStyle,
            ),
          ),
        ],
      ),
    );
  }
}

Now we can display the single post as we have used the Navigator push method.

As a result, it pushes the data through the class constructor.

If you want to clone this step please visit the respective branch of the GitHub repository.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Technical blog

Twitter

Comments

2 responses to “Flutter and WordPress: How to build a NewsApp”

  1. […] have also been able to display the latest posts on the home page. But this is not enough. For example, a post may belong to one or many […]

  2. […] the way, in previous sections, we have been building a News App where Flutter acts as the frontend. But the WordPress acts as the […]

Leave a Reply