Posted in

Разработка приложения для WordPress на Flutter (Dart)

Flutter — это мощный фреймворк для создания кроссплатформенных приложений, а WordPress — самая популярная система управления контентом. Их интеграция позволяет создать мобильное приложение для вашего WordPress-сайта с единой кодовой базой. В этой статье я подробно расскажу, как разработать такое приложение.

1. Подготовка WordPress

Перед разработкой приложения необходимо подготовить WordPress-сайт:

  1. Установите REST API плагин (если не активирован по умолчанию):

    • WordPress уже имеет встроенный REST API, но для расширенных функций можно установить плагины типа «WP REST API» или «JWT Authentication for WP-API».

  2. Настройка CORS:

    • Установите плагин «WP REST API — CORS» или добавьте в файл .htaccess:

      Header set Access-Control-Allow-Origin "*"
      Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
      Header set Access-Control-Allow-Headers "Content-Type, Authorization"
  3. Создайте пользователя для API:

    • Создайте отдельного пользователя с правами редактора или администратора для доступа через API.

2. Настройка проекта Flutter

  1. Создайте новый проект Flutter:

    flutter create wordpress_app
    cd wordpress_app
  2. Добавьте необходимые зависимости в pubspec.yaml:

    dependencies:
      flutter:
        sdk: flutter
      http: ^0.13.5
      flutter_html: ^3.0.0-alpha.6  # для отображения HTML-контента
      cached_network_image: ^3.2.3  # для кэширования изображений
      provider: ^6.0.5  # для управления состоянием
      shared_preferences: ^2.1.1  # для локального хранения данных
      flutter_dotenv: ^5.0.2  # для хранения конфигурации

3. Основная архитектура приложения

Создайте базовую структуру проекта:

lib/
├── models/          # Модели данных
├── services/        # Сервисы для работы с API
├── widgets/         # Кастомные виджеты
├── screens/         # Экраны приложения
├── utils/           # Вспомогательные утилиты
└── main.dart        # Точка входа

4. Работа с WordPress API

Создайте файл lib/services/wordpress_service.dart:

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

class WordPressService {
  final String baseUrl;

  WordPressService({required this.baseUrl});

  Future<List<dynamic>> getPosts({int perPage = 10, int page = 1}) async {
    final response = await http.get(
      Uri.parse('$baseUrl/wp-json/wp/v2/posts?per_page=$perPage&page=$page'),
    );

    if (response.statusCode == 200) {
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load posts');
    }
  }

  Future<dynamic> getPost(int id) async {
    final response = await http.get(
      Uri.parse('$baseUrl/wp-json/wp/v2/posts/$id'),
    );

    if (response.statusCode == 200) {
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load post');
    }
  }

  Future<List<dynamic>> getCategories() async {
    final response = await http.get(
      Uri.parse('$baseUrl/wp-json/wp/v2/categories'),
    );

    if (response.statusCode == 200) {
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load categories');
    }
  }
}

5. Создание моделей данных

Пример модели для поста (lib/models/post_model.dart):

class Post {
  final int id;
  final String title;
  final String content;
  final String excerpt;
  final String featuredImageUrl;
  final String date;
  final String author;
  final List<int> categories;

  Post({
    required this.id,
    required this.title,
    required this.content,
    required this.excerpt,
    required this.featuredImageUrl,
    required this.date,
    required this.author,
    required this.categories,
  });

  factory Post.fromJson(Map<String, dynamic> json) {
    return Post(
      id: json['id'],
      title: json['title']['rendered'],
      content: json['content']['rendered'],
      excerpt: json['excerpt']['rendered'],
      featuredImageUrl: json['featured_media'] != 0 
          ? json['_links']['wp:featuredmedia'][0]['href'] 
          : '',
      date: json['date'],
      author: json['_links']['author'][0]['href'],
      categories: List<int>.from(json['categories']),
    );
  }
}

6. Создание основных экранов

Пример экрана со списком постов (lib/screens/posts_screen.dart):

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/post_model.dart';
import '../services/wordpress_service.dart';

class PostsScreen extends StatefulWidget {
  
  _PostsScreenState createState() => _PostsScreenState();
}

class _PostsScreenState extends State<PostsScreen> {
  late Future<List<Post>> futurePosts;
  final ScrollController _scrollController = ScrollController();
  int _page = 1;
  List<Post> _posts = [];
  bool _isLoading = false;

  
  void initState() {
    super.initState();
    futurePosts = _fetchPosts();
    _scrollController.addListener(_scrollListener);
  }

  Future<List<Post>> _fetchPosts() async {
    final wordpressService = Provider.of<WordPressService>(context, listen: false);
    final data = await wordpressService.getPosts(page: _page);
    return data.map((json) => Post.fromJson(json)).toList();
  }

  void _scrollListener() {
    if (_scrollController.position.pixels == 
        _scrollController.position.maxScrollExtent) {
      _loadMorePosts();
    }
  }

  Future<void> _loadMorePosts() async {
    if (_isLoading) return;
    
    setState(() {
      _isLoading = true;
      _page++;
    });

    final newPosts = await _fetchPosts();
    
    setState(() {
      _posts.addAll(newPosts);
      _isLoading = false;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Последние статьи'),
      ),
      body: FutureBuilder<List<Post>>(
        future: futurePosts,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            _posts = snapshot.data!;
            return ListView.builder(
              controller: _scrollController,
              itemCount: _posts.length + (_isLoading ? 1 : 0),
              itemBuilder: (context, index) {
                if (index == _posts.length) {
                  return Center(child: CircularProgressIndicator());
                }
                final post = _posts[index];
                return ListTile(
                  title: Text(post.title),
                  subtitle: Text(post.excerpt),
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => PostDetailScreen(post: post),
                      ),
                    );
                  },
                );
              },
            );
          } else if (snapshot.hasError) {
            return Center(child: Text("Ошибка загрузки данных"));
          }
          return Center(child: CircularProgressIndicator());
        },
      ),
    );
  }

  
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }
}

7. Интеграция аутентификации

Для работы с защищенными endpoint’ами WordPress API:

  1. Установите JWT плагин на WordPress:

    • «JWT Authentication for WP-API»

  2. Добавьте методы аутентификации в WordPressService:

Future<String> login(String username, String password) async {
  final response = await http.post(
    Uri.parse('$baseUrl/wp-json/jwt-auth/v1/token'),
    body: {
      'username': username,
      'password': password,
    },
  );

  if (response.statusCode == 200) {
    final data = json.decode(response.body);
    return data['token'];
  } else {
    throw Exception('Login failed');
  }
}

Future<dynamic> createPost(Map<String, dynamic> data, String token) async {
  final response = await http.post(
    Uri.parse('$baseUrl/wp-json/wp/v2/posts'),
    headers: {
      'Authorization': 'Bearer $token',
      'Content-Type': 'application/json',
    },
    body: json.encode(data),
  );

  if (response.statusCode == 201) {
    return json.decode(response.body);
  } else {
    throw Exception('Failed to create post');
  }
}

8. Оптимизация производительности

  1. Кэширование данных:

    • Используйте shared_preferences или hive для локального хранения данных

    • Реализуйте стратегию «stale-while-revalidate»

  2. Оптимизация изображений:

    • Используйте cached_network_image для кэширования изображений

    • Реализуйте lazy loading для изображений

  3. Пагинация и бесконечная прокрутка:

    • Как показано в примере PostsScreen

9. Публикация приложения

  1. Настройте окружение:

    flutter pub get
    flutter pub run flutter_dotenv:generate
  2. Создайте файл .env:

    WORDPRESS_URL=https://your-site.com
  3. Запустите приложение:

    flutter run
  4. Соберите релизные версии:

    flutter build apk --release  # для Android
    flutter build ios --release  # для iOS

Заключение

Разработка приложения для WordPress на Flutter позволяет создать производительное кроссплатформенное решение с единой кодовой базой. Основные преимущества:

  • Доступ к полному функционалу WordPress через REST API

  • Высокая производительность и нативный пользовательский интерфейс

  • Возможность работы оффлайн с кэшированием данных

  • Единая кодовая база для iOS и Android

Для дальнейшего развития приложения можно добавить:

  • Push-уведомления через Firebase

  • Комментарии и формы

  • Поиск по контенту

  • Темную тему и другие настройки пользователя

Flutter предоставляет все необходимые инструменты для создания полноценного мобильного клиента вашего WordPress-сайта. Но все же это рекомендации! Изучайте документацию к языкам.

Добавить комментарий