Laravel Components

Part 1

Create a bootstrap project:

Create a new view under new components folder called master.blade.php. This HTML template taken from Bootstrap:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="https://getbootstrap.com/docs/4.0/assets/img/favicons/favicon.ico">

    <title>Blog Template for Bootstrap</title>

    <link rel="canonical" href="https://getbootstrap.com/docs/4.0/examples/blog/">

    <!-- Bootstrap core CSS -->
    <link href="https://getbootstrap.com/docs/4.0/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="https://fonts.googleapis.com/css?family=Playfair+Display:700,900" rel="stylesheet">
    <link href="{{asset('css/app.css')}}" rel="stylesheet">
    <link href="{{asset('css/blog.css')}}" rel="stylesheet">
  </head>

  <body>

    <div class="container">
      <header class="blog-header py-3">
        <div class="row flex-nowrap justify-content-between align-items-center">
          <div class="col-4 pt-1">
            <a class="text-muted" href="#">Subscribe</a>
          </div>
          <div class="col-4 text-center">
            <a class="blog-header-logo text-dark" href="#">Large</a>
          </div>
          <div class="col-4 d-flex justify-content-end align-items-center">
            <a class="text-muted" href="#">
              <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mx-3"><circle cx="10.5" cy="10.5" r="7.5"></circle><line x1="21" y1="21" x2="15.8" y2="15.8"></line></svg>
            </a>
            <a class="btn btn-sm btn-outline-secondary" href="#">Sign up</a>
          </div>
        </div>
      </header>

      <div class="nav-scroller py-1 mb-2">
        <nav class="nav d-flex justify-content-between">
          <a class="p-2 text-muted" href="#">World</a>
          <a class="p-2 text-muted" href="#">U.S.</a>
          <a class="p-2 text-muted" href="#">Technology</a>
          <a class="p-2 text-muted" href="#">Design</a>
          <a class="p-2 text-muted" href="#">Culture</a>
          <a class="p-2 text-muted" href="#">Business</a>
          <a class="p-2 text-muted" href="#">Politics</a>
          <a class="p-2 text-muted" href="#">Opinion</a>
          <a class="p-2 text-muted" href="#">Science</a>
          <a class="p-2 text-muted" href="#">Health</a>
          <a class="p-2 text-muted" href="#">Style</a>
          <a class="p-2 text-muted" href="#">Travel</a>
        </nav>
      </div>

      <div class="jumbotron p-3 p-md-5 text-white rounded bg-dark">
        <div class="col-md-6 px-0">
          <h1 class="display-4 font-italic">Title of a longer featured blog post</h1>
          <p class="lead my-3">Multiple lines of text that form the lede, informing new readers quickly and efficiently about what's most interesting in this post's contents.</p>
          <p class="lead mb-0"><a href="#" class="text-white font-weight-bold">Continue reading...</a></p>
        </div>
      </div>
    </div>

    <main role="main" class="container">
      <div class="row">
        <div class="col-md-8 blog-main">
          <h3 class="pb-3 mb-4 font-italic border-bottom">
            From the Firehose
          </h3>

          <div class="blog-post">
            <h2 class="blog-post-title">Sample blog post</h2>
            <p class="blog-post-meta">January 1, 2014 by <a href="#">Mark</a></p>

            <p>This blog post shows a few different types of content that's supported and styled with Bootstrap. Basic typography, images, and code are all supported.</p>
            <hr>
            <p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p>
            <blockquote>
              <p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
            </blockquote>
            <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
            <h2>Heading</h2>
            <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
            <h3>Sub-heading</h3>
            <p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p>
            <pre><code>Example code block</code></pre>
            <p>Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa.</p>
            <h3>Sub-heading</h3>
            <p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
            <ul>
              <li>Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</li>
              <li>Donec id elit non mi porta gravida at eget metus.</li>
              <li>Nulla vitae elit libero, a pharetra augue.</li>
            </ul>
            <p>Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.</p>
            <ol>
              <li>Vestibulum id ligula porta felis euismod semper.</li>
              <li>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</li>
              <li>Maecenas sed diam eget risus varius blandit sit amet non magna.</li>
            </ol>
            <p>Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis.</p>
          </div><!-- /.blog-post -->

          <div class="blog-post">
            <h2 class="blog-post-title">Another blog post</h2>
            <p class="blog-post-meta">December 23, 2013 by <a href="#">Jacob</a></p>

            <p>Cum sociis natoque penatibus et magnis <a href="#">dis parturient montes</a>, nascetur ridiculus mus. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed posuere consectetur est at lobortis. Cras mattis consectetur purus sit amet fermentum.</p>
            <blockquote>
              <p>Curabitur blandit tempus porttitor. <strong>Nullam quis risus eget urna mollis</strong> ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
            </blockquote>
            <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
            <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p>
          </div><!-- /.blog-post -->

          <div class="blog-post">
            <h2 class="blog-post-title">New feature</h2>
            <p class="blog-post-meta">December 14, 2013 by <a href="#">Chris</a></p>

            <p>Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Aenean lacinia bibendum nulla sed consectetur. Etiam porta sem malesuada magna mollis euismod. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
            <ul>
              <li>Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</li>
              <li>Donec id elit non mi porta gravida at eget metus.</li>
              <li>Nulla vitae elit libero, a pharetra augue.</li>
            </ul>
            <p>Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
            <p>Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue.</p>
          </div><!-- /.blog-post -->

          <nav class="blog-pagination">
            <a class="btn btn-outline-primary" href="#">Older</a>
            <a class="btn btn-outline-secondary disabled" href="#">Newer</a>
          </nav>

        </div><!-- /.blog-main -->

        <aside class="col-md-4 blog-sidebar">
          <div class="p-3 mb-3 bg-light rounded">
            <h4 class="font-italic">About</h4>
            <p class="mb-0">Etiam porta <em>sem malesuada magna</em> mollis euismod. Cras mattis consectetur purus sit amet fermentum. Aenean lacinia bibendum nulla sed consectetur.</p>
          </div>

          <div class="p-3">
            <h4 class="font-italic">Archives</h4>
            <ol class="list-unstyled mb-0">
              <li><a href="#">March 2014</a></li>
              <li><a href="#">February 2014</a></li>
              <li><a href="#">January 2014</a></li>
              <li><a href="#">December 2013</a></li>
              <li><a href="#">November 2013</a></li>
              <li><a href="#">October 2013</a></li>
              <li><a href="#">September 2013</a></li>
              <li><a href="#">August 2013</a></li>
              <li><a href="#">July 2013</a></li>
              <li><a href="#">June 2013</a></li>
              <li><a href="#">May 2013</a></li>
              <li><a href="#">April 2013</a></li>
            </ol>
          </div>

          <div class="p-3">
            <h4 class="font-italic">Elsewhere</h4>
            <ol class="list-unstyled">
              <li><a href="#">GitHub</a></li>
              <li><a href="#">Twitter</a></li>
              <li><a href="#">Facebook</a></li>
            </ol>
          </div>
        </aside><!-- /.blog-sidebar -->

      </div><!-- /.row -->

    </main><!-- /.container -->

    <footer class="blog-footer">
      <p>Blog template built for <a href="https://getbootstrap.com/">Bootstrap</a> by <a href="https://twitter.com/mdo">@mdo</a>.</p>
      <p>
        <a href="#">Back to top</a>
      </p>
    </footer>

    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery-slim.min.js"><\/script>')</script>
    <script src="../../assets/js/vendor/popper.min.js"></script>
    <script src="../../dist/js/bootstrap.min.js"></script>
    <script src="../../assets/js/vendor/holder.min.js"></script>
    <script>
      Holder.addTheme('thumb', {
        bg: '#55595c',
        fg: '#eceeef',
        text: 'Thumbnail'
      });
    </script>
  </body>
</html>

In the welcome view replace with a component like this:

<x-master>
</x-master>

Part 2

Cut everything inside blog-main class of master.blade.php and add inside these tags of welcome.blade.php

<x-master>
    @section('main-content')
    Code here
    @endsection
</x-master>

Between blog-main class will now look like:

        <div class="col-md-8 blog-main">
          @yield('main-content')
        </div>

You can further make the main content contain another component by creating a new component called <x-test></x-test> inside the new section. Then in components folder create a template called test.blade.php and add the content you want.

Part 3

Pass data to components

Open routes to add proper controller to the route:

Route::get('/', [App\Http\Controllers\HomeController::class, 'index']);

In home.blade.php add this:

<x-test :users="$users"></x-test>

In your test.blade.php add this:

@foreach($users as $user)
    {{$user->name}}
@endforeach

And finally add this to the HomeController.php

use App\Models\User;
    public function index()
    {
        $users = User::all();
        return view('home', ['users' => $users]);
        
    }

Show/Hide by toggling class

import React, { useState } from 'react';
import { BrowserRouter } from 'react-router-dom';
import './App.css';

function App() {
	var [showChat, setShowChat ] = useState('hide');
	var [showButton , setShowButton ] = useState('show');
	function handleChatShow() {
		setShowChat((showChat === "hide") ? "show" : "hide");
		setShowButton((showChat === "hide") ? "hide" : "show");
	}
	return (
		<>
			<button className={"open-button "+showButton} id="openchat" onClick={handleChatShow}></button>
			<div className={"chat_box form-container "+showChat} id="chatbubble">
				<button type="button" className="btn cancel" onClick={handleChatShow}>—</button>
				Text here
			</div>
		</>
	);
}
export default App;

Basic React Login using External API

API

We will use a free Login API from MeCallAPI.com with the following detail:

{
    "username": "karn.yong@mecallapi.com",
    "password": "mecallapi"
}
  • Response:
{
    "status": "ok",
    "message": "Logged in",
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
        "id": 1,
        "fname": "Karn",
        "lname": "Yong",
        "username": "karn.yong@mecallapi.com",
        "email": "karn.yong@mecallapi.com",
        "avatar": "https://www.mecallapi.com/users/1.png"
    }
}

For more APIs with populated fake data, such as user list and user profile authentication with JWT, these can be found at MeCallAPI.com.

Add packages

We will add the following packages to our application:

  • Material UI
  • react-router-dom
  • Sweetalert
npm i @material-ui/core @material-ui/icons react-router-dom sweetalert

Create screen for Sign-in

Create Sigin.js (From line 41 is the use of login API from MeCallAPI.com)

import React, { useState } from 'react';
import swal from 'sweetalert';
import './Login.css';

async function loginUser(credentials) {
	return fetch('https://www.mecallapi.com/api/login', {
		method: 'POST',
		headers: {
			'Content-Type': 'application/json'
		},
		body: JSON.stringify(credentials)
	})
    .then(data => data.json())
}

const Login = props => {
	const [username, setUserName] = useState();
	const [password, setPassword] = useState();
	const handleSubmit = async e => {
		e.preventDefault();
		const response = await loginUser({
			username,
			password
		});
		if ('accessToken' in response) {
			swal("Success", response.message, "success", {
				buttons: false,
				timer: 2000,
			})
			.then((value) => {
				localStorage.setItem('accessToken', response['accessToken']);
				localStorage.setItem('user', JSON.stringify(response['user']));
				window.location.href = "/admin";
			});
		} else {
			swal("Failed", response.message, "error");
		}
	}
	return (
		<>
			<div id="page-wrap" className="my-4 mx-4">
				<h1>Login</h1>
				<form noValidate onSubmit={handleSubmit}>
				  <div className="mb-3">
					<label for="email" className="form-label">Email address</label>
					<input
					  required
					  id="email"
					  name="email"
					  className="form-control"
					  aria-describedby="emailHelp"
					  onChange={e => setUserName(e.target.value)}
					/>
				  </div>
				  <div className="mb-3">
					<label for="password" className="form-label">Password</label>
					<input
					  id="password"
					  name="password"
					  type="password"
					  className="form-control"
					  onChange={e => setPassword(e.target.value)}
					/>
				  </div>
				  <div className="mb-3 form-check">
					<input type="checkbox" className="form-check-input" id="exampleCheck1" />
					<label className="form-check-label" for="exampleCheck1">Remember me</label>
				  </div>
				  <button type="submit" className="btn btn-primary">Submit</button>
				</form>
			</div>
		</>
	)
}
export default Login;

Now you can update your menu to show correct menu items for logged in/out states:

import React, { lazy } from 'react';
import { Link } from 'react-router-dom';
import './Sidebar.css';

const Menu = lazy(() => import('react-burger-menu/lib/menus/elastic'));


const Sidebar = props => {
	const isLoggedIn = localStorage.getItem('accessToken');
    
	const handleLogout = () => {
		localStorage.removeItem("accessToken");
		localStorage.removeItem("user");
		window.location.href = "/";
	};
	
	let adminLink, loggedLink;
    if (isLoggedIn) {
		adminLink = <Link className="menu-item" to="/admin">Admin</Link>;
		loggedLink = <div className="menu-item" onClick={handleLogout}>Logout</div>;
    } else {
		loggedLink = <Link className="menu-item" to="/login">Login</Link>;
    }
	
	return (
		<Menu>
      <Link className="menu-item" to="/">
        Home
      </Link>
      <Link className="menu-item" to="/favourites">
        Favourites
      </Link>
	  {adminLink}
	  {loggedLink}
    </Menu>
	);
}
export default Sidebar;

Toggle elements inside list of items

Hold ID of each row inside an array that you set when clicked. Use if statement inside JSX to check whether array has the ID value and show selected icon if it does, empty icon if it doesn’t.

const List = props => {
	var pagedList = props.pagedList;
	const [isFave, setIsFave] = useState([]);
	
	const selectFavourite = e => {
		const { id } = e.target;
		if(isFave.includes(id)){
			setIsFave(isFave.filter(item => item !== id));
		}else{
			setIsFave([...isFave, id]);
		}
    	}
	console.log(isFave);
    	return ( 
		<>
		{pagedList.map((row,i) => {
			return (
				<div key={i} className="list-card row">
					<div className="col-12 col-md g-0 list-content">
					<div 
						className="favouriteButton" 
						id={row.id_pg} 
						onClick={selectFavourite}
					>
						{isFave.includes(row.id_pg) ? <FavoriteIcon /> : <FavoriteBorderIcon /> }
					</div>
					</div>
				</div>
			);
		})}
		</>
    	);  
}  
export default List

Check all checkboxes

We get the checkboxes from an array of results called list. We use one of the array values to set the checked states and hold it in a variable called isCheck.

All checkboxes in the list have an onChange function called selectCheckbox which sets the checkbox ID in the isCheck array when checked and removes when unchecked.

IMPORTANT: To control the selecting all checkboxes, you need to add a checked attribute onto each individual checkbox that checks if the isCheck array includes the current array value.

In the main component below we have the select all checkbox. We have an onChange function called selectAll which toggles the true/false value for isCheckAll variable. Then it sets all checkboxes or empties all checkboxes array of isCheck depending on the true/false value of isCheckAll.

import React, { lazy, useEffect, useState } from 'react';
import axios from 'axios';

const MyList = lazy(() => import('../../components/MyList/MyList'));

const YourComponent = props => {
	const [isCheckAll, setIsCheckAll] = useState(false);
	const [isCheck, setIsCheck] = useState([]);
	var [list, setList] = useState([]);
	useEffect(() => {
		getRows()
	}, []);
	function getRows() {
		let getUrl = 'https://domain.com/getrows.php';
		axios({
			method: "get",
			url: getUrl,
		}).then((response) => {
			let data = response.data;
			setList(data.listRows);
		}, (error) => {
			console.log(error)
		})
	}
	const selectAll = e => {
		setIsCheckAll(!isCheckAll);
		setIsCheck(list.map(row => row.id_pg));
		if (isCheckAll) {
		  setIsCheck([]);
		}
	};
	return (
		<>
			<input
				id="selectAllCheckbox"
				name="selectAllCheckbox"
				type="checkbox"
				value=""
				className="form-check-input"
				onChange={selectAll}
			/>
			{list.length > 0 &&
			<MyList 
				list={list} 
				isCheck={isCheck}
				setIsCheck={setIsCheck.bind(this)} 
			/>
			}
		</>
	)
}
export default YourComponent;

Next create the checkboxes list component:

import React from 'react'
import './List.css'; 

const MyList = props => {
	var list= props.list;
	const isCheck = props.isCheck;

	const selectCheckbox = e => {
		const { id, checked } = e.target;
		props.setIsCheck([...isCheck, id]);
		if (!checked) {
			props.setIsCheck(isCheck.filter(item => item !== id));
		}
	};
	console.log(isCheck);
    return ( 
		<>
		{list.map((row,i) => {
			return (
			<div key={i} className="row">
				<div className="col-1">
					<input
						id={row.id_pg}
						name="select"
						type="checkbox"
						className="form-check-input"
						onChange={selectCheckbox}
						checked={isCheck.includes(row.id_pg)}
					/>
				</div>
				<div className="col-11">
				{row.name}
				</div>
			</div>
			);
		})}
		</>
    );  
}  
export default MyList

Rendering raw html with reactjs

dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM. In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.

It is better/safer to sanitise your raw HTML (using e.g., DOMPurify) before injecting it into the DOM via dangerouslySetInnerHTML.

DOMPurify – a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks.

import React from 'react'
import * as DOMPurify from 'dompurify';

const dropdownMenu = `
<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Another action</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Something else here</a></li>
    <li role="presentation"><a role="menuitem" tabindex="-1" href="#">Separated link</a></li>
  </ul>
</div>
`

const YourComponent = props => {
  <div>
    { <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(dropdownMenu) }} /> }
  </div>
}
export default YourComponent;
If the HTML is coming from user input, make sure it is sanitized!

Add new GA4 script to WordPress

<?php
add_action('wp_print_scripts', 'inline_scripts');
function inline_scripts(){
	//Only track if not logged in or is a customer
	global $current_user;
	if ( !isset( $current_user->roles[0] ) || $current_user->roles[0] == 'customer' ) {
	?>
	<!-- Google tag (gtag.js) -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=G-IDHERE"></script>
	<?php
	}
	?>
	<script>
	  window.dataLayer = window.dataLayer || [];
	  function gtag(){dataLayer.push(arguments);}
	  gtag('js', new Date());
	  gtag('config', 'G-IDHERE');
	</script>
	<?php
}

Regex

Short for regular expression, a regex is a string of text that lets you create patterns that help match, locate, and manage text.

Examples

Wildcard search in array with regex in PHP

$array = array('Michael','Marian','Martina');
$matching_letters = 'ri'; 
$array = preg_grep("/{$matching_letters}/i", $array);

Websites for regex pattern matching

Regex101.com 
PHPLiveRegex.com 

Get a List of All Users

Local user information is stored in the /etc/passwd file. Each line in this file represents login information for one user. To view file:

less /etc/passwd

If you want to display only the username you can use either awk or cut commands to print only the first field containing the username:

awk -F: '{ print $1}' /etc/passwd
cut -d: -f1 /etc/passwd