Build a Simple Web App with Express, React and GraphQL

This article was originally published on the Okta developer blog. Thank you for supporting the partners who make SitePoint possible.

GraphQL and React have both become quite popular in the last few years, and it’s safe to say they go together like avocado and toast. A GraphQL server can be written in Node and lets you easily create a flexible API using JavaScript classes and functions. When a frontend developer queries the server, only the information asked for gets processed. This means you can make the backend as robust as you want while keeping the frontend light by only requesting information needed for the page you’re viewing.

GraphQL is a relatively new standard for defining types and querying data, and there are quite a few different implementations of it, both server-side and client-side. Today I’ll show you how to use Express to create a GraphQL server, as well as how to create a single-page app in React that uses Apollo’s client to query the server.

Create the React App

The quickest way to get started with a React app is to use Create React App. If you don’t already have Node, Yarn, and Create React App installed, you can run the following commands:

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
npm install --global yarn create-react-app

Next, create and start a new app:

create-react-app graphql-express-react
cd graphql-express-react
yarn start

When you run create-react-app, you’ll get a new folder with everything you need to get started, and all the dependencies you need will be installed locally using yarn. When you type yarn start from within the folder, you’re starting the frontend development server that will automatically update whenever you edit any files.

create-react-app bootstrapped app

Create the GraphQL Server

Before we continue writing the frontend, you’ll need a server to connect to. Run the following commands to install the dependencies you’ll need to get up and running:

yarn add express@4.16.3 cors@2.8.4 graphql@14.0.2 express-graphql@0.6.12 graphql-tag@2.9.2

Create a new directory in your project’s src folder, named server:

mkdir src/server

In there, create a new file named index.js, with the following code:

const express = require('express');
const cors = require('cors');
const graphqlHTTP = require('express-graphql');
const gql = require('graphql-tag');
const { buildASTSchema } = require('graphql');

const POSTS = [
  { author: "John Doe", body: "Hello world" },
  { author: "Jane Doe", body: "Hi, planet!" },
];

const schema = buildASTSchema(gql`
  type Query {
    posts: [Post]
    post(id: ID!): Post
  }

  type Post {
    id: ID
    author: String
    body: String
  }
`);

const mapPost = (post, id) => post && ({ id, ...post });

const root = {
  posts: () => POSTS.map(mapPost),
  post: ({ id }) => mapPost(POSTS[id], id),
};

const app = express();
app.use(cors());
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: root,
  graphiql: true,
}));

const port = process.env.PORT || 4000
app.listen(port);
console.log(`Running a GraphQL API server at localhost:${port}/graphql`);

Let me explain the different parts of this code.

At the top of the file, you use the require tag to import your dependencies. Native Node doesn’t support the import tag yet, but you can use require instead. A future version of Node will likely support import. Create React App uses babel to transpile the code before running it, which allows you to use the import syntax in the React code, so you’ll see that when we get to the frontend code.

For now, this is just using some mock data, which is what the const POSTS contains. Each item contains an author and a body.

The gql tag allows your favorite code editor to realize that you’re writing GraphQL code so that it can stylize it appropriately. It also parses the string and converts it to GraphQL AST Abstract Syntax Tree. You then need to build a schema using buildASTSchema.

The GraphQL schema might be the most interesting part of this code. This is what defines the different types and allows you to say what the client can query. This will also automatically generate some very useful documentation so that you can just focus on coding.

type Query {
  posts: [Post]
  post(id: ID!): Post
}

type Post {
  id: ID
  author: String
  body: String
}

Here, you’ve defined a Post type, which contains an id, and author, and a body. You need to say what the types are for each element. Here, author and body both use the primitive String type, and id is an ID.

The Query type is a special type that lets you query the data. Here, you’re saying that posts will give you an array of Posts, but if you want a single Post you can query it by calling post and passing in the ID.

const mapPost = (post, id) => post && ({ id, ...post });

const root = {
  posts: () => POSTS.map(mapPost),
  post: ({ id }) => mapPost(POSTS[id], id),
};

You need to provide a set of resolvers to tell GraphQL how to handle the queries. When someone queries posts, it will run this function, providing an array of all the POSTS, using their index as an ID.

When you query post, it expects an id and will return the post at the given index.

const app = express();
app.use(cors());
app.use('/graphql', graphqlHTTP({
  schema,
  rootValue: root,
  graphiql: true,
}));

const port = process.env.PORT || 4000
app.listen(port);
console.log(`Running a GraphQL API server at localhost:${port}/graphql`);

Now you are able to create the server. The graphqlHTTP function creates an Express server running GraphQL, which expects the resolvers as rootValue, and the schema. The graphiql flag is optional and will run a server for you allowing you to more easily visualize the data and see the auto-generated documentation. When you run app.listen, you’re starting the GraphQL server.

To make sure we can easily run both the server and client at the same time, add the following dev dependencies:

yarn add -D nodemon@1.18.4 npm-run-all@4.1.3

Next, edit your package.json file so that the scripts section looks like this:

{
  "start": "npm-run-all --parallel watch:server start:web",
  "start:web": "react-scripts start",
  "start:server": "node src/server",
  "watch:server": "nodemon --watch src/server src/server",
  "build": "react-scripts build",
  "test": "react-scripts test --env=jsdom",
  "eject": "react-scripts eject"
},

Close your existing web server, then simply type yarn start again to run both the server and client at the same time. Whenever you make changes to the server, just the server will restart. Whenever you make changes to the frontend code, the page should automatically refresh with the latest changes.

Point your browser to http://localhost:4000/graphql to get the GraphiQL server. You can always come back here and refresh after changing some code around in the server to see the latest Schema and test your queries.

GraphiQL

Connect React to GraphQL

Next, you need to connect the frontend to GraphQL. I’ll use Bootstrap for some decent styling with minimal effort. Apollo makes a great React client that can link up to any GraphQL server. To install the dependencies you need for the frontend, run the following:

yarn add bootstrap@4.1.3 reactstrap@6.4.0 apollo-boost@0.1.16 react-apollo@2.1.11

You’ll need to configure the Apollo client to know where to connect to the backend. Create a new file src/apollo.js with the following code:

import ApolloClient from 'apollo-boost';

export default new ApolloClient({
  uri: "http://localhost:4000/graphql",
});

In order for Apollo’s Query React component to be able to connect using the client, the entire app needs to be wrapped in an ApolloProvider component. You’ll also want to include the styling for Bootstrap, and you can get rid of the index.css file that came with Create React App now. Make the following changes to your src/index.js file:

@@ -1,8 +1,17 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
-import './index.css';
+import { ApolloProvider } from 'react-apollo';
+
+import 'bootstrap/dist/css/bootstrap.min.css';
 import App from './App';
 import registerServiceWorker from './registerServiceWorker';
+import client from './apollo';

-ReactDOM.render(<App />, document.getElementById('root'));
+ReactDOM.render(
+  <ApolloProvider client={client}>
+    <App />
+  </ApolloProvider>,
+  document.getElementById('root')
+);
 serviceWorker.unregister();
+if (module.hot) module.hot.accept();

The module.hot.accept() isn’t really necessary, but makes it so that just the components changing within the app will refresh as you update them, rather than refreshing the entire page. Every once in a while you may need to refresh just to reset the state of the app, but generally, this leads to a quicker turnaround time.

Create a new file src/PostViewer.js that will fetch the data and render it in a table:

import React from 'react';
import gql from 'graphql-tag';
import { Query } from 'react-apollo';
import { Table } from 'reactstrap';

export const GET_POSTS = gql`
  query GetPosts {
    posts {
      id
      author
      body
    }
  }
`;

export default () => (
  <Query query={GET_POSTS}>
    {({ loading, data }) => !loading && (
      <Table>
        <thead>
          <tr>
            <th>Author</th>
            <th>Body</th>
          </tr>
        </thead>
        <tbody>
          {data.posts.map(post => (
            <tr key={post.id}>
              <td>{post.author}</td>
              <td>{post.body}</td>
            </tr>
          ))}
        </tbody>
      </Table>
    )}
  </Query>
);

The Query component requires a GraphQL query. In this case, you’re just getting all of the posts with their ID and the author and body. The Query component also requires a render function as its only child. It provides a loading state, but in our case, we just won’t show anything while it’s loading, since it will be really quick to fetch the data locally. Once it’s done loading, the data variable will be an object including the data you requested.

The above code renders a table (Table is a component that includes all the Bootstrap classes you need to make it look pretty) with all of the posts.

You should now change your src/App.js file to include the PostViewer component you just made. It should look like this:

import React, { Component } from 'react';

import PostViewer from './PostViewer';

class App extends Component {
  render() {
    return (
      <main>
        <PostViewer />
      </main>
    );
  }
}

export default App;

Now if you go to http://localhost:3000 you should see this:

plain table

Add the Ability to Edit Posts in GraphQL

In GraphQL, a query is typically read-only. If you want to modify data, you should use what’s known as a mutation instead.

Create a new Mutation type in your const schema in src/server/index.js to submit a post. You can create an input type to simplify your input variables. The new mutation should return the new Post on success:

type Mutation {
  submitPost(input: PostInput!): Post
}

input PostInput {
  id: ID
  author: String!
  body: String!
}

You’ll need to update your root variable to create a new resolver for submitPost as well. Add the following resolver:

submitPost: ({ input: { id, author, body } }) => {
  const post = { author, body };
  let index = POSTS.length;

  if (id != null && id >= 0 && id < POSTS.length) {
    if (POSTS[id].authorId !== authorId) return null;

    POSTS.splice(id, 1, post);
    index = id;
  } else {
    POSTS.push(post);
  }

  return mapPost(post, index);
},

If you provide an id, it will try to find the post at that index and replace the data with the author and body that was provided. Otherwise, it will add a new post. Then it returns the post you provided along with the new id for it. When you send a mutation request to GraphQL, you can define which pieces you want back:

submit post

For the frontend, you’ll need to create a new component for editing posts. Forms in React can be made easier by a library called Final Form. Install it with yarn:

yarn add final-form@4.10.0 react-final-form@3.6.5

Now, make a new file src/PostEditor.js and fill it with the following (I’ll explain it in more detail just below):

import React from 'react';
import gql from 'graphql-tag';
import {
  Button,
  Form,
  FormGroup,
  Label,
  Modal,
  ModalHeader,
  ModalBody,
  ModalFooter,
} from 'reactstrap';
import { Form as FinalForm, Field } from 'react-final-form';

import client from './apollo';
import { GET_POSTS } from './PostViewer';

const SUBMIT_POST = gql`
  mutation SubmitPost($input: PostInput!) {
    submitPost(input: $input) {
      id
    }
  }
`;

const PostEditor = ({ post, onClose }) => (
  <FinalForm
    onSubmit={async ({ id, author, body }) => {
      const input = { id, author, body };

      await client.mutate({
        variables: { input },
        mutation: SUBMIT_POST,
        refetchQueries: () => [{ query: GET_POSTS }],
      });

      onClose();
    }}
    initialValues={post}
    render={({ handleSubmit, pristine, invalid }) => (
      <Modal isOpen toggle={onClose}>
        <Form onSubmit={handleSubmit}>
          <ModalHeader toggle={onClose}>
            {post.id ? 'Edit Post' : 'New Post'}
          </ModalHeader>
          <ModalBody>
            <FormGroup>
              <Label>Author</Label>
              <Field
                required
                name="author"
                className="form-control"
                component="input"
              />
            </FormGroup>
            <FormGroup>
              <Label>Body</Label>
              <Field
                required
                name="body"
                className="form-control"
                component="input"
              />
            </FormGroup>
          </ModalBody>
          <ModalFooter>
            <Button type="submit" disabled={pristine} color="primary">Save</Button>
            <Button color="secondary" onClick={onClose}>Cancel</Button>
          </ModalFooter>
        </Form>
      </Modal>
    )}
  />
);

export default PostEditor;

The submitPost mutation is the new mutation to connect to the backend. It can use the PostInput type defined in the server:

const SUBMIT_POST = gql`
  mutation SubmitPost($input: PostInput!) {
    submitPost(input: $input) {
      id
    }
  }
`;

Final Form takes an onSubmit function that will pass in the data entered by the user. After the post is submitted, you’ll want to close the modal, so PostEditor takes an onClose prop to call when you’re done submitting.

Final Form also takes an initialValues object to define what values the form should initially have. In this case, the PostEditor component will take a post prop that has the variables you need in it, so that gets passed along as the initial values.

The other required prop is the render function, which will render the form. Final Form gives you a few useful form props so you can know if the form is valid or not, or if it’s been modified from the initialValues.

const PostEditor = ({ post, onClose }) => (
  <FinalForm
    onSubmit={/* ... */}
    initialValues={post}
    render={/* ... */}
  />
);

export default PostEditor;

In the onSubmit function, you’ll call the mutation needed to submit the post. Apollo lets you re-fetch queries. Since you know your list of posts will be out of date once you submit edits, you can re-fetch the GET_POSTS query here.

onSubmit={async ({ id, author, body }) => {
  const input = { id, author, body };

  await client.mutate({
    variables: { input },
    mutation: SUBMIT_POST,
    refetchQueries: () => [{ query: GET_POSTS }],
  });

  onClose();
}}

The render function will display a Bootstrap modal. This PostEditor component will only be rendered when you want it to be open, so isOpen is just set to true. Here you also use the onClose prop to close the modal when the user clicks outside the modal, hits Esc, or clicks the Cancel button.

The form needs to have the handleSubmit function passed to it as an onSubmit prop. This tells the form to go through Final Form instead of sending a POST request to the page.

Final Form also handles all the boilerplate needed to have a controlled input. Instead of storing the data in state whenever the user types something, you can just use the Field component.

render={({ handleSubmit, pristine, invalid }) => (
  <Modal isOpen toggle={onClose}>
    <Form onSubmit={handleSubmit}>
      <ModalHeader toggle={onClose}>
        {post.id ? 'Edit Post' : 'New Post'}
      </ModalHeader>
      <ModalBody>
        <FormGroup>
          <Label>Author</Label>
          <Field
            required
            name="author"
            className="form-control"
            component="input"
          />
        </FormGroup>
        <FormGroup>
          <Label>Body</Label>
          <Field
            required
            name="body"
            className="form-control"
            component="input"
          />
        </FormGroup>
      </ModalBody>
      <ModalFooter>
        <Button type="submit" disabled={pristine} color="primary">Save</Button>
        <Button color="secondary" onClick={onClose}>Cancel</Button>
      </ModalFooter>
    </Form>
  </Modal>
)}

Next, you’ll have to make a couple small changes to your PostViewer. This adds a hook to each row so that you can determine whether the row should be editable or not and if so, changes the styles a bit and lets you click on the row. Clicking on the row calls another callback, which you can use to set which post is being edited.

diff --git a/src/PostViewer.js b/src/PostViewer.js
index 5c53b5a..84177e0 100644
--- a/src/PostViewer.js
+++ b/src/PostViewer.js
@@ -13,7 +13,11 @@ export const GET_POSTS = gql`
   }
 `;

-export default () => (
+const rowStyles = (post, canEdit) => canEdit(post)
+  ? { cursor: 'pointer', fontWeight: 'bold' }
+  : {};
+
+const PostViewer = ({ canEdit, onEdit }) => (
   <Query query={GET_POSTS}>
     {({ loading, data }) => !loading && (
       <Table>
@@ -25,7 +29,11 @@ export default () => (
         </thead>
         <tbody>
           {data.posts.map(post => (
-            <tr key={post.id}>
+            <tr
+              key={post.id}
+              style={rowStyles(post, canEdit)}
+              onClick={() => canEdit(post) && onEdit(post)}
+            >
               <td>{post.author}</td>
               <td>{post.body}</td>
             </tr>
@@ -35,3 +43,10 @@ export default () => (
     )}
   </Query>
 );
+
+PostViewer.defaultProps = {
+  canEdit: () => false,
+  onEdit: () => null,
+};
+
+export default PostViewer;

Now, tie this all together in src/App.js. You can create a “New Post” button to create a new post, and make it so that you can edit any other existing post as well:

import React, { Component } from 'react';
import { Button, Container } from 'reactstrap';

import PostViewer from './PostViewer';
import PostEditor from './PostEditor';

class App extends Component {
  state = {
    editing: null,
  };

  render() {
    const { editing } = this.state;

    return (
      <Container fluid>
        <Button
          className="my-2"
          color="primary"
          onClick={() => this.setState({ editing: {} })}
        >
          New Post
        </Button>
        <PostViewer
          canEdit={() => true}
          onEdit={(post) => this.setState({ editing: post })}
        />
        {editing && (
          <PostEditor
            post={editing}
            onClose={() => this.setState({ editing: null })}
          />
        )}
      </Container>
    );
  }
}

export default App;

Add User Authentication to the React + GraphQL Web App

One simple way to add authentication to your project is with Okta. Okta is a cloud service that allows developers to create, edit, and securely store user accounts and user account data, and connect them with one or multiple applications. If you don’t already have one, sign up for a forever-free developer account. Log in to your developer console, navigate to Applications, then click Add Application. Select Single-Page App, then click Next.

Since Create React App runs on port 3000 by default, you should add that as a Base URI and Login Redirect URI. Your settings should look like the following:

create new application settings

Click Done to save your app, then copy your Client ID and paste it as a variable into a file called .env.local in the root of your project. This will allow you to access the file in your code without needing to store credentials in source control. You’ll also need to add your organization URL (without the -admin suffix). Environment variables (other than NODE_ENV) need to start with REACT_APP_ in order for Create React App to read them, so the file should end up looking like this:

.env.local

REACT_APP_OKTA_CLIENT_ID={yourClientId}
REACT_APP_OKTA_ORG_URL=https://{yourOktaDomain}

You’re also going to need an API token later for the server, so while you’re in there, navigate to API -> Tokens, then click on Create Token. You can have many tokens, so just give this one a name that reminds you what it’s for, like “GraphQL Express”. You’ll be given a token that you can only see right now. If you lose the token, you’ll have to create another one. Add this to .env also.

REACT_APP_OKTA_TOKEN={yourOktaAPIToken}

The easiest way to add Authentication with Okta to a React app is to use Okta’s React SDK. You’ll also need to add routes, which can be done using React Router.

yarn add @okta/okta-react@1.1.1 react-router-dom@4.3.1

In order to know if the user is authenticated, Okta requires the app to be wrapped in a Security component with some configuration. It also depends on React Router, so you’ll end up with a BrowserRouter component, wrapping a Security component, wrapping an ApolloProvider component, which finally wraps your App in a Route. Your src/index.js file should end up looking like this:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
import { Security, ImplicitCallback } from '@okta/okta-react';
import { ApolloProvider } from 'react-apollo';

import 'bootstrap/dist/css/bootstrap.min.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import client from './apollo';

ReactDOM.render(
  <BrowserRouter>
    <Security
      issuer={`${process.env.REACT_APP_OKTA_ORG_URL}/oauth2/default`}
      redirect_uri={`${window.location.origin}/implicit/callback`}
      client_id={process.env.REACT_APP_OKTA_CLIENT_ID}
    >
      <ApolloProvider client={client}>
        <Route path="/implicit/callback" component={ImplicitCallback} />
        <Route path="/" component={App} />
      </ApolloProvider>
    </Security>
  </BrowserRouter>,
  document.getElementById('root')
);
registerServiceWorker();
if (module.hot) module.hot.accept();

The Okta SDK comes with a withAuth higher order component (HoC) that can be used for a wide variety of auth-related things, but for this example, you’ll only need to know whether or not you’re authenticated, and some information about the user. To make this a little easier, I wrote a simple HoC to override the one that comes with the Okta SDK. Create a new file src/withAuth.js containing the following:

The post Build a Simple Web App with Express, React and GraphQL appeared first on SitePoint.


Source: Sitepoint

Preparing Your Content for the Extended Reality (XR) Future

This article on preparing for the XR future was originally published by Torque Magazine, and is reproduced here with permission.

You’ve probably heard rumblings in the tech industry around the innovations in Virtual Reality, Augmented Reality, and Mixed Reality. These mediums can broadly be defined as Extended Reality or XR.

My first venture into development in XR was in 2010 when I was exploring Flash development. My application was straightforward; show the webcam a Quick Response (QR) code and the program would superimpose a 3D model to the marker. In hindsight, this was such a life-changing moment for me. On top of being my first experience with manipulating digital 3D objects, it was also my first augmented reality experience accessible to the web.

The concept of a screen will likely be an afterthought in the coming years as we start blending the lines between our physical and digital selves. We will likely be surrounded by personalized versions of our environments and all of this personalization will be stored as meta in a database someplace. It is crucial for everyone to be able to have the power to control this meta and I’m optimistic WordPress will have a place in this because that’s where it really shines. WordPress allows you to do all of the hard things in content management with little knowledge of how it is working under the hood. I don’t need to know how to build a user system from the ground up…I can just use WordPress.

Content and meta will be a constant in our lives and, in my opinion, WordPress has secured a very nice spot in the future with the incorporation of the REST API. Anything that can make a HTTP request is now able to take data from WordPress and make intelligent decisions based on it. Maybe the structure of this approach will change in the coming years as different concepts such as GraphQL progress, but overall, the requirement of restful ways of handling data will likely remain constant for WordPress.

How Would an MVP WordPress Look in XR?

Last year, I sought to build a minimum viable VR WordPress using only the features we have available in a standard WordPress instance. I used Unity3D for my prototype as it was the lowest barrier to entry (FREE). The idea for this prototype was easy; use post data to populate UI elements in the VR world and use the featured 360 image of the post as a skybox around the user. My imagined use case for this was to be a mock travel blog.

Here’s what that looked like:

Here’s the flow of data and requisites:

Inspector settings

This really isn’t too rough of a concept. We make a REST call via C# using the WWW function. We take the data returned from WordPress and save it to a variable that the Unity Dev would assign using the simple drag and drop editor tooling. Unity takes the defined UI elements and applies the text stored in the variable to their mapped text object.

I’ve open sourced this project at the following repo. (Note: this was done in a two-day hackathon last year. This far from production ready code.)

The post Preparing Your Content for the Extended Reality (XR) Future appeared first on SitePoint.


Source: Sitepoint

Monthly Web Development Update 10/2018: The Hurricane Web, End-To-End-Integrity, And RAIL

Monthly Web Development Update 10/2018: The Hurricane Web, End-To-End-Integrity, And RAIL

Monthly Web Development Update 10/2018: The Hurricane Web, End-To-End-Integrity, And RAIL

Anselm Hannemann

2018-10-19T15:19:58+02:00
2018-10-19T13:34:15+00:00

With the latest studies and official reports out this week, it seems that to avoid an irreversible climate change on Planet Earth, we need to act drastically within the next ten years. This rose a couple of doubts and assumptions that I find worth writing about.

One of the arguments I hear often is that we as individuals cannot make an impact and that climate change is “the big companies’ fault”. However, we as the consumers are the ones who make the decisions what we buy and from whom, whose products we use and which ones we avoid. And by choosing wisely, we can make a change. By talking to other people around you, by convincing your company owner to switch to renewable energy, for example, we can transform our society and economy to a more sustainable one that doesn’t harm the planet as much. It will be a hard task, of course, but we can’t deny our individual responsibility.

Maybe we should take this as an occasion to rethink how much we really need. Maybe going out into nature helps us reconnect with our environment. Maybe building something from hand and with slow methods, trying to understand the materials and their properties, helps us grasp how valuable the resources we currently have are — and what we would lose if we don’t care about our planet now.

News

  • Chrome 70 is here with Desktop Progressive Web Apps on Windows and Linux, public key credentials in the Credential Management API, and named Workers.
  • Postgres 11 is out and brings more robustness and performance for partitioning, enhanced capabilities for query parallelism, Just-in-Time (JIT) compilation for expressions, and a couple of other useful and convenient changes.
  • As the new macOS Mojave and iOS 12 are out now, Safari 12 is as well. What’s new in this version? A built-in password generator, a 3D and AR model viewer, icons in tabs, web pages on the latest watch OS, new form field attribute values, the Fullscreen API for iOS on iPads, font collection support in WOFF2, the font-display loading CSS property, Intelligent Tracking Prevention 2.0, and a couple of security enhancements.
  • Google’s decision to force users to log into their Google account in the browser to be able to access services like Gmail caused a lot of discussions. Due to the negative feedback, Google promptly announced changes for v70. Nevertheless, this clearly shows the interests of the company and in which direction they’re pushing the app. This is unfortunate as Chrome and the people working on that project shaped the web a lot in the past years and brought the ecosystem “web” to an entirely new level.
  • Microsoft Edge 18 is out and brings along the Web Authentication API, new autoplay policies, Service Worker updates, as well as CSS masking, background blend, and overscroll.

General

  • Max Böck wrote about the Hurricane Web and what we can do to keep users up-to-date even when bandwidth and battery are limited. Interestingly, CNN and NPR provided text-only pages during Hurricane Florence to serve low traffic that doesn’t drain batteries. It would be amazing if we could move the default websites towards these goals — saving power and bandwidth — to improve not only performance and load times but also help the environment and make users happier.

UI/UX

Redesign portfolio website
Shawn Parks shares the lessons he learned from redesigning his portfolio every year. (Image credit)

Accessibility

Tooling

Privacy

  • Guess what? Our simple privacy-enhancing tools that delete cookies are useless as this article shows. There are smarter ways to track a user via TLS session tracking, and we don’t have much power to do anything against it. So be aware that someone might be able to track you regardless of how many countermeasures you have enabled in your browser.
  • Josh Clark’s comment on university research about Google’s data collection is highlighting the most important parts about how important Android phone data is to Google’s business model and what type of information they collect even when your smartphone is idle and not moving location.

Security

End-to-End Integrity with IPFS illustrated with cats and dogs
Cloudflare’s IPFS gateway allows a website to be end-to-end secure while maintaining the performance and reliability benefits of being served from their edge network. (Image credit)

Web Performance

Illustration of the RAIL model
The four parts of the RAIL performance model: Response, Animation, Idle, Load. (Image credit)

HTML & SVG

JavaScript

  • Willian Martins shares the secrets of JavaScript’s bind() function, a widely unknown operator that is so powerful and allows us to invoke this from somewhere else into named, non-anonymous functions. A different way to write JavaScript.
  • Everyone knows what the “9am rush hour” means. Paul Lewis uses the term to rethink how we build for the web and why we should try to avoid traffic jams on the main thread of the browser and outsource everything that doesn’t belong to the UI into separate traffic lanes instead.

CSS

An item placed inside a grid using negative grid lines
Did you know you can use negative grid line numbers to position Grid items with CSS? (Image credit)

Work & Life

Going Beyond…

  • In the Netherlands, there’s now a legal basis that prescribes CO2 emissions to be cut by 25% by 2020 (that’s just a bit more than one year from now). I love the idea and hope other countries will be inspired by it — Germany, for example, which currently moves its emission cut goals farther and farther into the future.
  • David Wolpert explains why computers use so much energy and how we could make them vastly more efficient. But for that to happen, we need to understand the thermodynamics of computing better.
  • Turning down twenty billion dollars is cool. Of course, it is. But the interesting point in this article about the Whatsapp founder who just told the world how unhappy he is having sold his service to Facebook is that it seems that he believed he could keep the control over his product.

One more thing: I’m very grateful for all of you who helped raise my funding level for the Web Development Reading List to 100% this month. I never got so much feedback from you and so much support. Thank you! Have a great month!

—Anselm

Smashing Editorial
(cm)


Source: Smashing Magazine

How to Enrich Data with MongoDB Stitch

This article was originally published on MongoDB. Thank you for supporting the partners who make SitePoint possible.

Here is what we are going to achieve in this tutorial:

Firstly, we are going to write a document to MongoDB using MongoDB Stitch.

The result in our MongoDB collection will look like this:

{
"_id": ObjectId("5bb27712dced5f37bebf388c"),
"Title":"Guardians of the Galaxy"
}

Secondly, a trigger will catch this new insertion and start a function.

Lastly, this function will call the OMDB external API with the given movie title, fetch data about that movie, and finally enrich our MongoDB document with the data we gathered from this API.

This is the final result we expect in our MongoDB collection:

{  
   "_id": ObjectId("5bb27712dced5f37bebf388c"),
   "Title":"Guardians of the Galaxy",
   "Year":"2014",
   "Rated":"PG-13",
   "Released":"01 Aug 2014",
   "Runtime":"121 min",
   "Genre":"Action, Adventure, Comedy",
   "Director":"James Gunn",
   "Writer":"James Gunn, Nicole Perlman, Dan Abnett (based on the Marvel comics by), Andy Lanning (based on the Marvel comics by), Bill Mantlo (character created by: Rocket Raccoon), Keith Giffen (character created by: Rocket Raccoon), Jim Starlin (characters created by: Drax the Destroyer,  Gamora & Thanos), Steve Englehart (character created by: Star-Lord), Steve Gan (character created by: Star-Lord), Steve Gerber (character created by: Howard the Duck), Val Mayerik (character created by: Howard the Duck)",
   "Actors":"Chris Pratt, Zoe Saldana, Dave Bautista, Vin Diesel",
   "Plot":"A group of intergalactic criminals are forced to work together to stop a fanatical warrior from taking control of the universe.",
   "Language":"English",
   "Country":"USA",
   "Awards":"Nominated for 2 Oscars. Another 52 wins & 99 nominations.",
   "Poster":"https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg",
   "Ratings":[  
      {  
         "Source":"Internet Movie Database",
         "Value":"8.1/10"
      },
      {  
         "Source":"Rotten Tomatoes",
         "Value":"91%"
      },
      {  
         "Source":"Metacritic",
         "Value":"76/100"
      }
   ],
   "Metascore":"76",
   "imdbRating":"8.1",
   "imdbVotes":"871,949",
   "imdbID":"tt2015381",
   "Type":"movie",
   "DVD":"09 Dec 2014",
   "BoxOffice":"$270,592,504",
   "Production":"Walt Disney Pictures",
   "Website":"http://marvel.com/guardians",
   "Response":"True"
}

Prerequisites

So first of all, if you want to try this at home, it is very easy. The only requirement here is to create a free MongoDB Atlas cluster. This video will show you the steps.

MongoDB Stitch is our serverless platform, built by MongoDB on top of MongoDB Atlas. Once our MongoDB Atlas cluster is ready to use, link a MongoDB Stitch application to it:

  • Click on the left panel on “Stitch Apps”,

  • Then click on “Create New Application”,

  • Pick the name you want for your application,

  • Link it to your free MongoDB Atlas cluster.

Actions

To be able to send a document to MongoDB, we are going to use an HTTP POST service.

  • On the left panel, click on “Services”,
  • Then click on “Add a Service”,
  • Choose a service name “IMDB”,

Note: “IMDB” will be reuse later in the function code. If you choose another name, please make sure to update the code accordingly.

  • Click on “Add Service”,

  • Click on “Add Incoming Webhook”,

  • And copy the screenshot below.

When this is done, hit the “Save” button and you will be in the “Function Editor” screen.

Enter the following code:

exports = function(payload, response) {
  const mongodb = context.services.get("mongodb-atlas");
  const movies = mongodb.db("stitch").collection("movies");
  var body = EJSON.parse(payload.body.text());
  movies.insertOne(body)
  .then(result => {
    response.setStatusCode(201);
  });
};

Click the “Save” button again.

Now that our Service is ready, we can test it!

Go to the “Settings” and you will find your Webhook URL. You can now send an HTTP POST request like this to MongoDB Stitch:

curl -H "Content-Type: application/json" -d '{"Title":"Guardians of the Galaxy"}' https://webhooks.mongodb-stitch.com/api/client/v2.0/app/stitchtapp-abcde/service/IMDB/incoming_webhook/post_movie_title?secret=test

Note: I used a curl command but feel free to use Postman or whatever you are used to.

We can check it worked by having a look at the content of the “stitch.movies” collection in our MongoDB Atlas Cluster:

Now that we can insert a new document into MongoDB Atlas using Stitch, we are going to create the trigger.

The post How to Enrich Data with MongoDB Stitch appeared first on SitePoint.


Source: Sitepoint

Improving Native WordPress Search

This article on WordPress search was originally published by Torque Magazine, and is reproduced here with permission.

If you have ever worked on a WordPress site with a massive amount of posts and pages, you might have noticed something about the WordPress search: it doesn’t perform well. In this article, we dive into why the default WordPress search doesn’t scale and some ways to make it better.

How WordPress Searches

By default, the native WordPress search performs a query on your database that looks something like this:

A native WordPress database search query

Let’s break down this query a little bit.

  • First, we are using SQL_CALC_FOUND_ROWS on the wp_posts table. This says, if there were no limit (coming later), how many results would the following query turn up?
  • Then we search through the post_title, post_excerpt, and post_content columns for the search term (in this example I searched “tech”).
  • And we ensure that the content returned is a post, page, or attachment (media).
  • We check to make sure the status is “public”–not deleted or private (if you are a logged-in user it will also search only your own private posts).
  • We order the results by matching title, descending, or post date, descending.
  • Last, we limit the results to 10, paginating the rest of the results.

That’s a whole lot of checks WordPress runs through just to return search results. And every time you iterate through wp_posts to perform each check, MySQL is processing all rows in wp_posts. When you have hundreds of thousands of rows in the wp_posts table, this query can get ugly really quick. Here are some benchmarks from a few of my sites:

Bar graph showing query times per number of posts

On sites with a very large number of posts, the query took over 20 seconds! This is not a scalable search option for sites with high traffic.

Problem Identification

Knowing what we now know about the default search behavior, it’s important to call out why this might not be ideal for some websites.

  • WordPress only searches the “post_title,” “post_content,” and “post_excerpt” fields for your search terms. It also only presents “post,” “page,” and “attachment” post types. For users with custom post types, custom fields, or plugins like WooCommerce that add different page/post types, this can be problematic: these items will not appear in search results.
  • The query used by WordPress search performs very poorly at over 100,000 posts. For news sites or media sites with more than 100,000 posts, a search could take several seconds to perform.
  • The poor performance on the search query could cause server performance issues if your site receives a fair amount of search traffic.

Improving on WordPress Native Search

So now that we know WordPress native search isn’t an option for many sites, we can explore search solutions. Based on our problem identification above, our qualifications for a search solution include:

  • Search tools that will search all content or customized sets of content, not limited to the post types or post fields defined by default.
  • Search tools that perform well when presented with large data sets.
  • Search tools that will not cause poor server performance when presented with high traffic.

Below we will explore several solutions, including enterprise-grade external services and WordPress plugins.

Algolia Search

Algolia is an enterprise-grade search solution in which your posts and content are indexed offsite and returns results to your users. Its feature set includes fuzzy search, geolocation search, multi-language support, and search with synonyms.

Comparing search performance on a site with thousands of posts, there are some clear benefits with Algolia. Below is the performance of the default WordPress search:

DevTool view of the default WordPress search performance

Notice the search took 7.43 seconds using the default WordPress search. However, after implementing Algolia search the results were nearly instant:

DevTool view of Algolia search performance

The Algolia results were about 15x faster than standard WordPress search! That is a massive improvement in performance. Not to mention, if the site supports a large amount of traffic with concurrent searches, it will not cause strain on the server. Offloading searches to an external service that is specifically optimized for searching is a big win.

The post Improving Native WordPress Search appeared first on SitePoint.


Source: Sitepoint

Reasons Your Mobile App Retention Rate Might Be So Low

Reasons Your Mobile App Retention Rate Might Be So Low

Reasons Your Mobile App Retention Rate Might Be So Low

Suzanne Scacca

2018-10-18T14:00:01+02:00
2018-10-18T12:41:47+00:00

In business, there’s a lot of talk about generating customer loyalty and retaining the business of good customers. Mobile apps aren’t all that different when you think about it.

While the number of installs may signal that an app is popular with users initially, it doesn’t tell the whole story. In order for an app to be successful, it must have loyal subscribers that make use of the app as it was intended. Which is where the retention rate enters the picture.

In this article, I want to explore what a good retention rate looks like for mobile apps. I’ll dig into the more common reasons why mobile apps have low retention rates and how those issues can be fixed.

Let’s start with the basics.

Checking The Facts: What Is A Good Mobile App Retention Rate?

A retention rate is the percentage of users that remain active on your mobile app after a certain period of time. It doesn’t necessarily pertain to how many people have uninstalled the app either. A sustained lack of activity is generally accepted as a sign that a user has lost interest in an app.

To calculate a good retention rate for your mobile app, be sure to take into account the frequency of logins you expect users to make. Some apps realistically should see daily logins, especially for gaming, dating, and social networking. Others, though, may only need weekly logins, like for ride-sharing apps, Google Authenticator or local business apps.

When calculating the retention rate for anticipated daily usage, you should run the calculation for at least a week, if not more. For weekly or monthly usage, adjust your calculation accordingly.

Recommended reading: Driving App Engagement With Personalization Techniques

For daily usage, divide the following like so:

Users Logged into the App on Day 0
Users Logged into the App on Day 1
Users Logged into the App on Day 2
Users Logged into the App on Day 3
Users Logged into the App on Day 4
Users Logged into the App on Day 5
Users Logged into the App on Day 6
Users Logged into the App on Day 7

This will give you a curve that demonstrates how well your mobile app is able to sustain users. Here is an example of how you would calculate this:

Number of New Users Acquired
Day 0100
Day 191 (91% )
Day 285 (85%)
Day 370 (70%)
Day 460 (60%)
Day 549 (49%)
Day 632 (32%)
Day 731 (31%)

If you can, add the data into a line graph format. It’ll be much easier to spot trends in downward momentum or plateauing:


example retention rate
An example of how to calculate and chart your app’s retention rate (Image source: Google Docs) (Large preview)

This is just a basic example of how a retention rate calculation works. Curious to see what the average (Android) mobile app’s retention curve looks like?

A Quettra study (with Andrew Chen) charted the following:


average Android app retention rate
Average retention rates for Android apps (Image source: Andrew Chen) (Large preview)

According to this data, the average app loses 77% of users within just three days. By the time the first-month wraps, 90% of those original new users are gone.

Recent data shows that the average cost per installation of a mobile app (globally) breaks down to the following:


average cost per app install
Average cost of each mobile app installation (Image source: Statista) (Large preview)

Basically, this is the average cost to build and market an app — a number you should aim to recuperate per user once the app has been installed. However, if your app loses about 90% of its users within a month’s time, think about what the loss actually translates to for your business.

Ankit Jain of Gradient Ventures summarized the key lesson to take away from these findings:

“Users try out a lot of apps but decide which ones they want to ‘stop using’ within the first 3-7 days. For ‘decent’ apps, the majority of users retained for 7 days stick around much longer. The key to success is to get the users hooked during that critical first 3-7 day period.”

As you can see from the charting of the top Android apps, Jain’s argument holds water:


average retention rate for top Android apps
Average retention rates for top Android apps (Image source: Andrew Chen) (Large preview)

Top Android apps still see a sharp decline in active users after about three days, but then the numbers plateau. They also don’t bleed as many new users upfront, which allows them to sustain a larger percentage of users.

This is exactly what you should be aiming for.

A Retention Recovery Guide For Mobile Apps

So, we know what makes for a good and bad retention rate. We also understand that it’s not about how many people have uninstalled or deleted the app from their devices. Letting an app sit in isolation, untouched on a mobile device, is just as bad.

As you can imagine, increasing your retention rate will lead to other big wins for your mobile app:

  • More engagement
  • More meaningful engagement
  • Greater loyalty
  • Increased conversions (if your app is monetized, that is)

Now you need to ask yourself:

“When are users dropping off? And why?”

You can draw your own hypotheses about this based on the retention rate alone, though it might be helpful to make use of tools like heat maps to spot problem areas in the mobile app. Once you know what’s going on, you can take action to remove the friction from the user experience.

To get you started, I’ve included a number of issues that commonly plague mobile apps with low retention rates. If your app is guilty of any of these, get to work on fixing the design or functionality ASAP!

1. Difficult Onboarding

Aside from the app store description and screenshots users encounter, onboarding is the first real experience they have with a mobile app. As you can imagine, a frustrating sign-in or onboarding procedure could easily turn off those who take that as a signal the rest of the app will be as difficult to use.

Let’s use the OkCupid dating app as an example. The initial splash screen looks great and is well-designed. It has a clear value proposition, and an easy-to-find call-to-action:


Splash screen for OkCupid app
The first screen new OkCupid users encounter (Image source: OkCupid) (Large preview)

On the next page, users are given two options for joining the app. It’s free to use, but still requires users to create an account:


OkCupid account creation
Account creation for OkCupid gives two options (Image source: OkCupid) (Large preview)

The first option is a Facebook sign-in. The other is to use a personal email address. Since Facebook logins can streamline not just signup, but the setup of dating mobile apps (since users can automatically import details, photos, and connections), this option is probably one many users’ choose.

But there’s a problem with it: After seven clicks to connect to Facebook and confirm one’s identity, here is what the user sees (or, at least, this is what I encountered the last couple of times I tried):


Signup error with OkCupid
After connecting to Facebook, users still encounter an error signing in. (Image source: OkCupid) (Large preview)

One of the main reasons why users choose a Facebook sign-in is because of how quick and easy it’s supposed to be. In these attempts of mine, however, my OkCupid app wouldn’t connect to Facebook. So, after 14 total clicks (7 for each time I tried to sign up), I ended up having to provide an email anyway.

This is obviously not a great first impression OkCupid has left on me (or any of its users). What makes it worse is that we know there’s a lot more work to get onboarded with the app. Unlike competitors like Bumble that have greatly simplified signup, OkCupid forces users into a buggy onboarding experience as well as a more lengthy profile configuration.

Needless to say, this is probably a bit too much for some users.

2. Slow or Sloppy Navigation

Here’s another example of a time-waster for mobile app users.

Let’s say getting inside the new app is easy. There’s no real onboarding required. Maybe you just ask if it’s okay to use their location for personalization purposes or if you can send push notifications. Otherwise, users are able to start using the app right away.

That’s great — until they realize how clunky the experience is.

To start, navigation of a mobile app should be easy and ever-present. It’s not like a browser window where users can hit that “Back” button in order to get out of an unwanted page. On a mobile app, they need a clear and intuitive exit strategy. Also, navigation of an app should never take more than two or three steps to get to a desired outcome.

One example of this comes from Wendy’s. Specifically, I want to look at the “Offers” user journey:


Offers from Wendy’s app
The home page of the Wendy’s app promises “Offers” (Image source: Wendy’s) (Large preview)

As you can see, the navigation at the bottom of the app is as clear as day. Users have three areas of the app they can explore — each of which makes sense for a business like Wendy’s. There are three additional navigation options in the top-right corner of the app, too.

When “Offers” is clicked, users are taken to a sort of full-screen pop-up containing all current special deals:


Wendy’s Offers pop-up
The Wendy’s Offers pop-up screen (Image source: Wendy’s) (Large preview)

As you can see, the navigation is no longer there. The “X” for the Offers pop-up also sits in the top-left corner (instead of the right, which is the more intuitive choice). This is already a problem. It also persists throughout the entire Offers redemption experience.

Let’s say that users aren’t turned off by the poor navigational choices and still want to redeem one of these offers. This is what they encounter next:


Wendy’s in-restaurant offers
Wendy’s Offers can be used at the restaurant. (Image source: Wendy’s) (Large preview)

Now, this is pretty cool. Users can redeem the offer at that very moment while they’re in a Wendy’s or they can place the order through the app and pick it up. Either way, this is a great way to integrate the mobile app and in-store experiences.

Except…


Wendy’s offer code
The Wendy’s offer code takes a while to populate. (Image source: Wendy’s) (Large preview)

Imagine standing in line at a Wendy’s or going through a drive-thru that isn’t particularly busy. That image above is not one you’d want to see.

They call it “fast food” for a reason and if your app isn’t working or it takes just a few seconds too long to load the offer code, imagine what that will do for everyone else’s experience at Wendy’s. The cashiers will be annoyed that they’ve held up the flow of traffic and everyone waiting in line will be frustrated in having to wait longer.

While mobile apps generally are designed to cater to the single user experience, you do have to consider how something like this could affect the experience of others.

Recommended reading: How To Improve Your Billing Form’s UX In One Day

3. Overwhelming Navigation

A poorly constructed or non-visible navigation is one thing. But a navigation that gives way too many options can be just as problematic. While a mega menu on something like an e-commerce website certainly makes sense, an oversized menu in mobile apps doesn’t.

It pains me to do this since I love the BBC, but its news app is guilty of this crime:


BBC News navigation
The top of the BBC News navigation (Image source: BBC News) (Large preview)

This looks like a standard news navigation at first glance. Top (popular) stories sit at the top; my News (customized) stories below it. But then it appears there’s more, so users are apt to scroll downwards and see what others options there are:


More BBC News pages
More of the BBC News navigation bar (Image source: BBC News) (Large preview)

The next scroll down gives users a choice of stories by geography, by subject:


Even more BBC News pages
Even more BBC News pages to choose from. (Image source: BBC News) (Large preview)

And then there are even more options for sports as well as specific BBC News channels. It’s a lot to take in.

If that weren’t bad enough, the personalization choices mirror the depth of the navigation:


BBC News personalization
BBC News personalization choices (Image source: BBC News) (Large preview)

Now, there’s nothing wrong with personalizing the mobile app experience. I think it’s something every app — especially those that deliver global news — should allow for. However, BBC News gives an overwhelming amount of options.

What’s worse is that many of the stories overlap categories, which means users could realistically see the same headlines over and over again as they scroll through the personalized categories they’ve chosen.

If BBC News (or any other app that does this) wants to allow for such deep personalization, the app should be programmed to hide stories that have already been seen or scrolled past — much like how Feedly handles its stream of news. That way, all that personalization really is valuable.

Recommended reading: How BBC Interactive Content Works Across AMP, Apps, And The Web

4. Outdated or Incomplete Experience

Anything a mobile app does that makes users unwillingly stop or slow down is bad. And this could be caused by a number of flaws in the experience:

  • Slow-loading pages,
  • Intrusive pop-ups,
  • Dated design choices,
  • Broken links or images,
  • Incomplete information,
  • And so on.

If you expect users to take time to download and at least give your app a try, make sure it’s worth their while.

One such example of this is the USHUD mobile app. It’s supposed to provide the same exact experience to users as the website counterpart. However, the app doesn’t work all that well:


Slow USHD app
A slow-loading page on the USHUD app (Image source: USHUD) (Large preview)

In the example above, you can see that search results are slow to load. Now, if they were chock full of images and videos, I could see why that might occur (though it’s still not really acceptable).

That said, many of the properties listed on the app don’t have corresponding visual content:


USHUD missing images
USHUD is missing images in search. (Image source: USHUD) (Large preview)

Real estate apps or, really, any apps that deal in the transaction of purchasing or renting of property or products should include images with each listing. It’s the whole reason why consumers are able to rent and buy online (or at least use it in the decisionmaking process).

But this app seems to be missing many images, which can lead to an unhelpful and unpleasant experience for users who hope to get information from the more convenient mobile app option.

If you’re going to build a mobile app that’s supposed to inform and compel users to engage, make sure it’s running in tip-top shape. All information is available. All tabs are accessible. And pages load in a reasonable timeframe.

5. Complicated or Impossible Gestures

We’ve already seen what a poorly made navigation can do to the user experience as well as the problem with pages that just don’t load. But sometimes friction can come from intentionally complicated gestures and engagements.

This is something I personally encountered with Sinemia recently. Sinemia is a competitor of the revolutionary yet failing MoviePass mobile app. Sinemia seems like a reasonable deal and one that could possibly sustain a lot longer than the unrealistic MoviePass model that promises entry to one movie every single day. However, Sinemia has had many issues with meeting the demand of its users.

To start, it delayed the sending of cards by a week. When I signed up in May, I was told I would have to wait at least 60 days to receive my card in the mail, even though my subscription had already kicked in. So, there was already a disparity there.

Sinemia’s response to that was to create a “Cardless” feature. This would enable those users who hadn’t yet received their cards to begin using their accounts. As you can see here, the FAQ included a dedicated section to Sinemia Cardless:


Sinemia FAQ
Questions about Sinemia Cardless (Image source: Sinemia) (Large preview)

See that point that says “I can confirm I have the latest Sinemia release installed…”? The reason why that point is there is because many Sinemia Cardless users (myself included) couldn’t actually activate the Cardless feature. When attempting to do so, the app would display an error.

The Sinemia FAQ then goes on to provide this answer to the complaint/question:


Sinemia Cardless issues
Sinemia Cardless issues with app version (Image source: Sinemia) (Large preview)

Here’s the problem: there were never any updates available for the mobile app. So, I and many others reached out to Sinemia for support. The answer repeatedly given was that Cardless could not work if your app ran on an old version. Support asked users to delete the app from their devices and reinstall from the app store to ensure they had the correct version — to no avail.

For me, this was a big problem. I was paying for a service that I had no way of using, and I was spending way too much time uninstalling and installing an app that should work straight out the gate.

I gave up after 48 hours of futile attempts. I went to my Profile to delete my account and get a refund on the subscription I had yet to use. But the app told me it was impossible to cancel my account through it. I tried to ask support for help, but no one responded. So, after Googling similar issues with account cancellations, I found that the only channel through which Sinemia would handle these requests was Facebook Messenger.

Needless to say, the whole experience left me quite jaded about apps that can’t do something as simple as activating or deactivating an account. While I recognize an urge to get a better solution on the mobile app market, rushing out an app and functionality that’s not ready to reach the public isn’t the solution.

Recommended reading: What You Need To Know About OAuth2 And Logging In With Facebook

6. Gated Content Keeps App from Being Valuable

For those of you who notice your retention rate remaining high for the first week or so from installation, the problem may more have to do with the mobile app’s limitations.

Recolor is a coloring book app I discovered in the app store. There’s nothing in the description that would lead me to believe that the app requires payment in order to enjoy the calming benefits of coloring pictures, but that’s indeed what I encountered:


Free coloring book images
Free drawings users can color with the Recolor app. (Image source: Recolor) (Large preview)

Above, you can see there are a number of free drawings available. Some of the more complex drawings will take some time to fill in, but not as much as a physical coloring book would by hand, which means users are apt to get through this quickly.

Inevitably, mobile app users will go searching for more options and this is what they will encounter:


Recolor is pay to play
Recolor’s more popular options are for Premium users. (Image source: Recolor) (Large preview)

When users look into some of the more popular drawings from Recolor, you’d hope they would encounter at least a few free drawings, right? After all, how many users could possibly be paying for a subscription to this app that’s not outrightly advertised as premium?

But it’s not just the Popular choices that require a fee to access (that’s what the yellow symbol in the bottom-right means). So, too, do most of the other categories:


Recolor’s premium offerings
Premium account needed to access more drawings on Recolor. (Image source: Recolor) (Large preview)

It’s a shame that so much of the content is gated off. Coloring books have proven to be good for managing anxiety and stress, so leaving users with only a few dozen options doesn’t seem right. Plus, the weekly membership to the app is pretty expensive, even if users try to earn coins by watching videos.

A mobile app such as this one should make its intentions clear from the start: “Consider this a free trial. If you want more, you’ll have to pay.”

While I’m sure the developer didn’t intend to deceive with this app model, I can see how the retention rate might suffer and prevent this app from becoming a long-term staple on many users’ devices.

When making a promise to users (even if it’s implied), design and manage your app in a way that lives up to those expectations.

As I noted earlier, those initial signups might make you hopeful of the app’s long-term potential, but a forced pay-to-play scenario could easily disrupt that after just a few weeks.

7. Impossible to Convert in-App

Why do we create mobile apps? For many developers, it’s because the mobile web experience is insufficient. And because many users want a more convenient way to connect with your brand. A mobile app sits on the home screen of devices and requires just a single click to get inside.

So, why would someone build an app that forces users to leave it in order to convert? It seems pointless to even go through the trouble of creating the app in the first place (which is usually no easy task).

Here’s the Megabus app:


Megabus ticket search
The Megabus mobile app for searching and buying tickets (Image source: Megabus) (Large preview)

Megabus is a low-cost transportation service that operates in Canada, the United States and the United Kingdom. There are a number of reasons why users would gravitate to the mobile app counterpart for the website; namely, the convenience of logging in and purchasing tickets while they’re traveling.

The image above shows the search I did for Megabus tickets through the mobile app. I entered all pertinent details, found tickets available for my destination and got ready to “Buy Tickets” right then and there.

However, you can’t actually buy tickets from the mobile app:


Megabus tickets
Megabus tickets are only available online. (Image source: Megabus) (Large preview)

Upon clicking “Buy Tickets”, the app pushes users out and into their browser. They then are asked to reinput all those details from the mobile app to search for open trips and make a purchase.

For a service that’s supposed to make travel over long distances convenient, its mobile app has done anything but reinforce that experience.

For those of you considering building an app (whether on your own accord or because a client asked) solely so you can land a spot in app store search results, don’t waste users’ time. If they can’t have a complete experience within the app, you’re likely to see your retention rate tank fairly quickly.

Wrapping Up

Clearly, there are a number of ways in which a mobile app may suffer a misstep in terms of the user experience. And I’m sure that there are times when mobile app developers don’t even realize there’s something off in the experience.

This is why your mobile app retention rate is such a critical data point to pay attention to. It’s not enough to just know what that rate is. You should watch for when those major dropoffs occur; not just in terms of the timeline, but also in terms of which pages lead to a stoppage in activity or an uninstall altogether.

With this data in hand, you can refine the in-app experience and make it one that users want to stay inside of for the long run.

Smashing Editorial
(ra, yk, il)


Source: Smashing Magazine

New Course: Build an App With JavaScript and the MEAN Stack

You can make your web development work a whole lot easier by taking advantage of the MEAN stack (MongoDB, Express, Angular, and Node.js). Find out how in our comprehensive new course, Build an App From Scratch With JavaScript and the MEAN Stack

What You’ll Learn

Full-stack web development requires coding both a front-end for the browser and a back-end server. Using JavaScript for both parts of the app makes life a lot simpler for full-stack devs. With the MEAN technologies, you can code a cutting-edge web app in JavaScript, from the front-end all the way down to the database.

In this detailed 3.5-hour course, Derek Jensen will show you how to use the MEAN technologies to build full-stack web apps using only JavaScript (and its close cousin TypeScript). You’ll start from absolute scratch, scaffolding an empty project, and build up a complete web app using the MEAN stack. 

App created with the MEAN stack

You’ll learn how to configure a MongoDB database, how to write a database abstraction layer, and how to create a REST API to make that data available to the front-end. On the client side, you’ll learn how to structure an Angular app, how to create a service to connect with the back-end API, and how to implement each of the UI components that make a complete app.

Watch the Introduction

 

Take the Course

You can take our new course straight away with a subscription to Envato Elements. For a single low monthly fee, you get access not only to this course, but also to our growing library of over 1,000 video courses and industry-leading eBooks on Envato Tuts+. 

Plus you now get unlimited downloads from the huge Envato Elements library of 700,000+ creative assets. Create with unique fonts, photos, graphics and templates, and deliver better projects faster.


Source: Nettuts Web Development

How to Deploy to Alibaba Cloud ECS with Mina

This article was created in partnership with Alibaba Cloud. Thank you for supporting the partners who make SitePoint possible.

Do you have a tip for making the most out of Alibaba Cloud Services? If so, tell us about it in our SitePoint Community.

Mina is a fast deployer and server automation tool, with advanced features and powerful extensibility. Learn how Mina can make your deployment process better, how to install it, how to extend it with plugins, and run through your first automated workflow. Then learn how to use Mina to migrate databases and websites, and set up even more advanced workflows with tools like WP CLI. We’ll be using Alibaba Cloud ECS for this tutorial.

To learn more about Mina, check out our article here.

The post How to Deploy to Alibaba Cloud ECS with Mina appeared first on SitePoint.


Source: Sitepoint

How Culture Can Influence the Success of Your Business

After graduating from university, Lisa Spiden — the founder of FibreHR and Roster Right — embarked on a backpacking trip across Europe before eventually landing in London and, consequently, into Human Resources with HSBC Investment Bank and BC Global.

From there, she worked with several large organizations before taking on her first “commercial” human resources role with retail giant The Just Group, which largely influenced her understanding of how company culture affects business outcomes. It was the first role where Lisa experienced a true “sense of achievement” by being able to implement strategies and immediately see their effect on people and sales in store.

You could literally go into store the next day and see how it was actually affecting the people, you could see if it was actually working and if people were enjoying what you were doing – you could actually tell if it was making a difference to the business.

Recognized as an industry talent, several businesses soon approached Lisa to work as an HR consultant, which led to the launch of her first business, FibreHR. After working with big brands like Carmen’s and kikki.K, and having also launched her second business, Roster Right, one of the most important lessons Lisa has learned over the years is that culture begins from “minute one” and will always reflect the behavior of its leaders.

Gimmicks like basketball courts or “Friday night drinks” might sound appealing, and they can be great incentives, but they don’t ensure a positive or effective work environment on their own. Culture is created by both leaders and staff following the values of the business.

The post How Culture Can Influence the Success of Your Business appeared first on SitePoint.


Source: Sitepoint

How to Translate WordPress Websites Using the Weglot Plugin

This article on how to translate WordPress websites was originally published by Torque Magazine, and is reproduced here with permission.

Translating your WordPress website into other languages is a smart way to reach a wider audience and increase your traffic. If your site is only available in a single language, you could be losing out on a lot of potential leads and conversions.

Fortunately, you don’t need to speak multiple languages to translate your site – the process of doing so is simple with the Weglot Translate plugin. Using this, you can automatically translate every part of your WordPress site, and manually fine-tune your translations in a snap.

In this article, we’ll discuss why you might want to translate your website. Then we’ll introduce the Weglot Translate plugin and its key features, and walk you through how to use it to add more languages to your site. We’ll also explore some of the plugin’s key customization options. Let’s get started!

Why You Should Translate Your WordPress Website

It’s estimated that there are nearly 7,000 different languages in the world, and yet over half of all websites use just a single one: English. This makes some degree of sense, as it’s the language most commonly spoken by internet users. However, it’s by far the only one. In terms of the number of speakers, it’s almost tied with Chinese, which appears on less than 2 percent of all websites. Similarly, while half a billion users speak Spanish, only just over 5 percent of sites use the language.

In a nutshell, by only delivering your site in English, you’re effectively limiting its scope. If your site has an international focus, such as an e-commerce business, you shouldn’t expect all users to be fluent in a single language. Therefore, many sites are taking steps to provide translated content in order to become more welcoming to a wider audience. For example, WordPress has its Polyglots team, who are working to translate the platform into as many languages as possible.

Beyond making your site more accessible, translating it also has a number of benefits for you:

With all this in mind, you should think about making your site more international. However, before you do, let’s look at some key considerations.

What You Need to Consider Before Translating Your Site

Before you translate your site, there are some things you should bear in mind. First, you need to think about implementation and compatibility. We’ll discuss this in more detail later, but you need to use a solution that is easy to implement on your site, such as a WordPress plugin.

You also need to consider which languages you want to use. This can be done by investigating your site’s analytics to see where your visitors are based. You should also perform keyword research with a focus on multilingual keywords. This should give you a solid idea of who your visitors are, and which languages may help you grow your audience.

We also recommend researching ‘language pairs’. Basically, this is a combination of the language your content is currently in, and the potential translated language. In short, consider the most common language pairs and which ones make the most sense for your site.

Finally, you need to find a translation solution that works for you. Let’s look at some right now.

A Look at WordPress-Specific Translation Solutions

The most basic way you can translate your website is to simply hire a translator. While this can yield good results, it’s not without problems. You’d likely need a translator for each language you’d like to use, which can get expensive. If your site is quite big, it would also take a significant amount of time, not to mention the upkeep as your site grows.

A more efficient option is to use machine translation. If you’ve ever used Google Translate, you’ll be familiar with the concept. Essentially, this is an automatic process that translates your site without human interaction. This is a lot less time-consuming and often cheaper, but it’s also notoriously imperfect. For this reason, you need to ensure the solution you use enables you to customize the generated translations.

There are several WordPress plugins you can use, such as Weglot Translate, WPML, and Polylang. You need to make sure the plugin you choose is compatible with both your site and your other plugins. For instance, if your site runs WooCommerce and your plugin is incompatible, large chunks of content will be left untranslated.

Introducing Weglot Translate

Weglot website download page

Weglot Translate is a plugin that enables you to automatically create a fully-translated version of your entire WordPress site. This plugin is one of the easiest options available to use and can translate your site in seconds. It offers over 100 different languages and is fully compatible with all themes and plugins, including e-commerce solutions such as WooCommerce. Weglot also has links to professional translators, giving you the option of ordering translations if required.

Key Features

  • Translates your entire WordPress site and is fully compatible with any theme or plugin, including WooCommerce.
  • Requires minimal configuration due to the quick plug-and-play setup.
  • Automatically applies Google’s SEO best practices for multilingual pages.
  • Gives you full control over your content and translations, enabling easy collaboration.

Price: Weglot offers a free version and several premium plans, starting at around $12 (€9.90) per month.

How to Translate Your WordPress Website Using the Weglot Translate Plugin

Let’s now put all of this theory into practice by translating a site using Weglot Translate. We’ll be using a site running WooCommerce and the Storefront theme, but Weglot Translate is compatible with all WordPress sites, regardless of theme and plugins.

Our site is currently only available in English but we want to create a version in Swedish. Here’s the original site:

Our original untranslated site

To start, you’ll need to download, install, and activate the Weglot Translate plugin from the WordPress.org Plugin Directory.

Weglot in the plugin directory

Next, you’ll need an API key, which you can get for free by signing up for a Weglot account. You’ll see your API key appear, as well as a link to your personal dashboard. We’ll return to that in a minute, but for now, copy your key and return to your WordPress site.

Grabbing your API key

The post How to Translate WordPress Websites Using the Weglot Plugin appeared first on SitePoint.


Source: Sitepoint