Nothing
# espn_wnba_transactions.R
# WNBA-only ESPN endpoint wrappers:
# espn_wnba_draft(), espn_wnba_freeagents(), espn_wnba_transactions()
# These endpoints have no WBB equivalent, so they are implemented directly
# without shared helpers.
# ---------------------------------------------------------------------------
# espn_wnba_draft
# ---------------------------------------------------------------------------
#' **Get ESPN WNBA Draft Picks**
#' @name espn_wnba_draft
NULL
#' @title
#' **Get ESPN WNBA Draft Picks**
#' @rdname espn_wnba_draft
#' @author Saiem Gilani
#' @param season Season year (numeric, e.g. 2025). Defaults to the most
#' recent WNBA season.
#' @param ... Additional arguments; currently unused but retained for
#' forward compatibility. Proxy configuration should use
#' `options(wehoop.proxy = ...)`.
#' @return A `wehoop_data` tibble with one row per draft pick:
#'
#' \if{html}{\tabular{lll}{
#' col_name \tab types \tab description \cr
#' season \tab integer \tab Season identifier (4-digit year or 'YYYY-YY' string). \cr
#' round \tab integer \tab Tournament / playoff round. \cr
#' pick \tab integer \tab Pick. \cr
#' overall \tab integer \tab Overall. \cr
#' traded \tab logical \tab Traded. \cr
#' trade_note \tab character \tab Trade note. \cr
#' status \tab character \tab Status label. \cr
#' athlete_id \tab character \tab Unique athlete identifier (ESPN). \cr
#' athlete_ref \tab character \tab Athlete ref. \cr
#' team_id \tab character \tab Unique team identifier. \cr
#' team_ref \tab character \tab Team ref. \cr
#' }}
#' \if{latex}{See the HTML help or pkgdown reference for the column table.}
#'
#' Athlete and team details (name, position, college, abbreviation) are not
#' inlined in the draft response; resolve them via `espn_wnba_player_info()`
#' or `espn_wnba_team()` using the returned IDs.
#'
#' @importFrom jsonlite fromJSON
#' @importFrom janitor clean_names
#' @importFrom dplyr as_tibble mutate
#' @importFrom rlang %||%
#' @import rvest
#' @export
#' @family ESPN WNBA Functions
#' @details
#' Calls the ESPN core-v2 endpoint
#' `https://sports.core.api.espn.com/v2/sports/basketball/leagues/wnba/seasons/{year}/draft/rounds`,
#' which returns each round of the draft with its picks inlined as `picks: [...]`.
#' For historical seasons with no ESPN draft data the function returns an empty
#' tibble rather than erroring.
#' @examples
#' \donttest{
#' espn_wnba_draft(season = 2024)
#' }
espn_wnba_draft <- function(season = most_recent_wnba_season(), ...) {
.args <- mget(setdiff(names(formals()), "..."))
picks_df <- data.frame(stringsAsFactors = FALSE)
# Parse the trailing path-segment ID out of an ESPN $ref URL, e.g.
# ".../athletes/108565?lang=..." -> "108565".
.ref_id <- function(ref, segment) {
if (is.null(ref) || is.na(ref) || !nzchar(ref)) return(NA_character_)
m <- regmatches(ref, regexec(paste0("/", segment, "/(\\d+)"), ref))[[1]]
if (length(m) >= 2) m[[2]] else NA_character_
}
tryCatch(
expr = {
# /draft itself returns {rounds, athletes, ...} (no top-level items).
# /draft/rounds returns a paged collection where each item is a round
# carrying its picks inline as `picks: [...]`.
rounds_url <- paste0(
"https://sports.core.api.espn.com/v2/sports/basketball/leagues/wnba",
"/seasons/", as.integer(season), "/draft/rounds"
)
res <- .retry_request(rounds_url)
check_status(res)
raw <- res %>% .resp_text() %>% jsonlite::fromJSON(simplifyDataFrame = FALSE)
rounds <- raw[["items"]]
if (is.null(rounds) || length(rounds) == 0) {
picks_df <- data.frame(stringsAsFactors = FALSE) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Draft Picks from ESPN.com", Sys.time())
return(picks_df)
}
pick_rows <- list()
for (rd in rounds) {
round_no <- as.integer(rd[["number"]] %||% NA_integer_)
picks <- rd[["picks"]]
if (is.null(picks) || length(picks) == 0) next
for (pk in picks) {
ath_ref <- pk[["athlete"]][["$ref"]] %||% NA_character_
team_ref <- pk[["team"]][["$ref"]] %||% NA_character_
pick_rows[[length(pick_rows) + 1L]] <- data.frame(
season = as.integer(season),
round = round_no,
pick = as.integer(pk[["pick"]] %||% NA_integer_),
overall = as.integer(pk[["overall"]] %||% NA_integer_),
traded = isTRUE(pk[["traded"]]),
trade_note = as.character(pk[["tradeNote"]] %||% NA_character_),
status = as.character(pk[["status"]][["name"]] %||% NA_character_),
athlete_id = .ref_id(ath_ref, "athletes"),
athlete_ref = as.character(ath_ref),
team_id = .ref_id(team_ref, "teams"),
team_ref = as.character(team_ref),
stringsAsFactors = FALSE
)
}
}
if (length(pick_rows) == 0) {
picks_df <- data.frame(stringsAsFactors = FALSE) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Draft Picks from ESPN.com", Sys.time())
return(picks_df)
}
picks_df <- do.call(rbind, pick_rows) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Draft Picks from ESPN.com", Sys.time())
},
error = function(e) .report_api_error(
e,
hint = paste0("Failed to retrieve ESPN WNBA draft data for season ", season),
args = .args
),
warning = function(w) .report_api_warning(
w,
hint = paste0("Warning retrieving ESPN WNBA draft data for season ", season),
args = .args
),
finally = {}
)
return(picks_df)
}
# ---------------------------------------------------------------------------
# espn_wnba_freeagents
# ---------------------------------------------------------------------------
#' **Get ESPN WNBA Free Agents**
#' @name espn_wnba_freeagents
NULL
#' @title
#' **Get ESPN WNBA Free Agents**
#' @rdname espn_wnba_freeagents
#' @author Saiem Gilani
#' @param season Season year (numeric, e.g. 2025). Defaults to the most
#' recent WNBA season.
#' @param ... Additional arguments; currently unused but retained for
#' forward compatibility. Proxy configuration should use
#' `options(wehoop.proxy = ...)`.
#' @return A `wehoop_data` tibble with one row per free agent:
#'
#' \if{html}{\tabular{lll}{
#' col_name \tab types \tab description \cr
#' season \tab integer \tab Season identifier (4-digit year or 'YYYY-YY' string). \cr
#' athlete_id \tab character \tab Unique athlete identifier (ESPN). \cr
#' athlete_name \tab character \tab Athlete display name (ESPN). \cr
#' position \tab character \tab Listed roster position (G, F, C, etc.). \cr
#' prior_team_id \tab character \tab Unique identifier for prior team. \cr
#' status \tab character \tab Status label. \cr
#' signed_team_id \tab character \tab Unique identifier for signed team. \cr
#' signed_date \tab character \tab Date in YYYY-MM-DD format. \cr
#' contract_value \tab character \tab Contract value. \cr
#' contract_term_years \tab character \tab Contract term years. \cr
#' }}
#' \if{latex}{See the HTML help or pkgdown reference for the column table.}
#'
#' @importFrom jsonlite fromJSON
#' @importFrom janitor clean_names
#' @importFrom dplyr as_tibble
#' @importFrom rlang %||%
#' @import rvest
#' @export
#' @family ESPN WNBA Functions
#' @details
#' Calls the ESPN core-v2 endpoint
#' `https://sports.core.api.espn.com/v2/sports/basketball/leagues/wnba/seasons/{year}/freeagents`.
#' As of 2026-05, this endpoint returns HTTP 500 for every season tested and
#' there is no documented replacement; the function consequently returns an
#' empty tibble and emits a CLI error message. It is retained so that downstream
#' code does not break if ESPN restores the endpoint, but should not be relied
#' on in the meantime.
#' @examples
#' \donttest{
#' espn_wnba_freeagents(season = 2025)
#' }
espn_wnba_freeagents <- function(season = most_recent_wnba_season(), ...) {
.args <- mget(setdiff(names(formals()), "..."))
fa_df <- data.frame(stringsAsFactors = FALSE)
tryCatch(
expr = {
url <- paste0(
"https://sports.core.api.espn.com/v2/sports/basketball/leagues/wnba",
"/seasons/", as.integer(season), "/freeagents"
)
res <- .retry_request(url)
check_status(res)
raw <- res %>%
.resp_text() %>%
jsonlite::fromJSON(simplifyDataFrame = TRUE)
items <- raw[["items"]]
if (is.null(items) || (is.data.frame(items) && nrow(items) == 0) ||
(is.list(items) && length(items) == 0)) {
fa_df <- data.frame(stringsAsFactors = FALSE) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Free Agents from ESPN.com", Sys.time())
return(fa_df)
}
if (!is.data.frame(items)) {
items <- as.data.frame(items, stringsAsFactors = FALSE)
}
# Extract nested athlete fields
athlete_id <- NA_character_
athlete_name <- NA_character_
if ("athlete" %in% colnames(items)) {
ath <- items[["athlete"]]
if (is.data.frame(ath)) {
athlete_id <- as.character(ath[["id"]] %||% NA_character_)
athlete_name <- as.character(ath[["displayName"]] %||% NA_character_)
} else if (is.list(ath)) {
athlete_id <- vapply(ath, function(a) {
as.character(if (is.list(a) || is.data.frame(a)) a[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
athlete_name <- vapply(ath, function(a) {
as.character(if (is.list(a) || is.data.frame(a)) a[["displayName"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
position_val <- NA_character_
if ("position" %in% colnames(items)) {
pos <- items[["position"]]
if (is.data.frame(pos)) {
position_val <- as.character(pos[["abbreviation"]] %||% NA_character_)
} else if (is.list(pos)) {
position_val <- vapply(pos, function(p) {
as.character(if (is.list(p) || is.data.frame(p)) p[["abbreviation"]] %||% NA_character_ else NA_character_)
}, character(1))
} else {
position_val <- as.character(pos)
}
}
prior_team_id <- NA_character_
if ("team" %in% colnames(items)) {
tm <- items[["team"]]
if (is.data.frame(tm)) {
prior_team_id <- as.character(tm[["id"]] %||% NA_character_)
} else if (is.list(tm)) {
prior_team_id <- vapply(tm, function(t) {
as.character(if (is.list(t) || is.data.frame(t)) t[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
signed_team_id <- NA_character_
if ("signedTeam" %in% colnames(items)) {
stm <- items[["signedTeam"]]
if (is.data.frame(stm)) {
signed_team_id <- as.character(stm[["id"]] %||% NA_character_)
} else if (is.list(stm)) {
signed_team_id <- vapply(stm, function(t) {
as.character(if (is.list(t) || is.data.frame(t)) t[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
get_scalar_col <- function(df, col) {
if (col %in% colnames(df)) as.character(df[[col]]) else rep(NA_character_, nrow(df))
}
fa_df <- data.frame(
season = as.integer(season),
athlete_id = athlete_id,
athlete_name = athlete_name,
position = position_val,
prior_team_id = prior_team_id,
status = get_scalar_col(items, "status"),
signed_team_id = signed_team_id,
signed_date = get_scalar_col(items, "signedDate"),
contract_value = get_scalar_col(items, "contractValue"),
contract_term_years = get_scalar_col(items, "contractTermYears"),
stringsAsFactors = FALSE
) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Free Agents from ESPN.com", Sys.time())
},
error = function(e) .report_api_error(
e,
hint = "Failed to retrieve ESPN WNBA free agents for season {season}",
args = .args
),
warning = function(w) .report_api_warning(
w,
hint = "Warning retrieving ESPN WNBA free agents for season {season}",
args = .args
),
finally = {}
)
return(fa_df)
}
# ---------------------------------------------------------------------------
# espn_wnba_transactions
# ---------------------------------------------------------------------------
#' **Get ESPN WNBA Transactions**
#' @name espn_wnba_transactions
NULL
#' @title
#' **Get ESPN WNBA Transactions**
#' @rdname espn_wnba_transactions
#' @author Saiem Gilani
#' @param season Season year (numeric, e.g. 2025). Defaults to the most
#' recent WNBA season.
#' @param limit Maximum number of transactions to return (integer). Default
#' `100`.
#' @param ... Additional arguments; currently unused but retained for
#' forward compatibility. Proxy configuration should use
#' `options(wehoop.proxy = ...)`.
#' @return A `wehoop_data` tibble with one row per transaction:
#'
#' \if{html}{\tabular{lll}{
#' col_name \tab types \tab description \cr
#' transaction_id \tab character \tab Unique identifier for transaction. \cr
#' date \tab character \tab Date in YYYY-MM-DD format. \cr
#' type \tab character \tab Record type / category. \cr
#' description \tab character \tab Long-form description text. \cr
#' team_id \tab character \tab Unique team identifier. \cr
#' athlete_id \tab character \tab Unique athlete identifier (ESPN). \cr
#' athlete_name \tab character \tab Athlete display name (ESPN). \cr
#' from_team_id \tab character \tab Unique identifier for from team. \cr
#' to_team_id \tab character \tab Unique identifier for to team. \cr
#' }}
#' \if{latex}{See the HTML help or pkgdown reference for the column table.}
#'
#' @importFrom jsonlite fromJSON
#' @importFrom janitor clean_names
#' @importFrom dplyr as_tibble
#' @importFrom rlang %||%
#' @import rvest
#' @export
#' @family ESPN WNBA Functions
#' @details
#' Calls the ESPN site-v2 endpoint
#' `https://site.api.espn.com/apis/site/v2/sports/basketball/wnba/transactions?season={year}&limit={limit}`.
#' Releases have a `NULL` `to_team_id`; those are stored as `NA`. Returns an
#' empty tibble rather than erroring when no transactions are available.
#' @examples
#' \donttest{
#' espn_wnba_transactions(season = 2025, limit = 10)
#' }
espn_wnba_transactions <- function(
season = most_recent_wnba_season(),
limit = 100,
...) {
.args <- mget(setdiff(names(formals()), "..."))
tx_df <- data.frame(stringsAsFactors = FALSE)
tryCatch(
expr = {
url <- paste0(
"https://site.api.espn.com/apis/site/v2/sports/basketball/wnba",
"/transactions?season=", as.integer(season),
"&limit=", as.integer(limit)
)
res <- .retry_request(url)
check_status(res)
raw <- res %>%
.resp_text() %>%
jsonlite::fromJSON(simplifyDataFrame = TRUE)
items <- raw[["transactions"]]
if (is.null(items)) items <- raw[["items"]]
if (is.null(items) || (is.data.frame(items) && nrow(items) == 0) ||
(is.list(items) && length(items) == 0)) {
tx_df <- data.frame(stringsAsFactors = FALSE) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Transactions from ESPN.com", Sys.time())
return(tx_df)
}
if (!is.data.frame(items)) {
items <- as.data.frame(items, stringsAsFactors = FALSE)
}
# Nested field extractors
athlete_id <- NA_character_
athlete_name <- NA_character_
if ("athlete" %in% colnames(items)) {
ath <- items[["athlete"]]
if (is.data.frame(ath)) {
athlete_id <- as.character(ath[["id"]] %||% NA_character_)
athlete_name <- as.character(ath[["displayName"]] %||% NA_character_)
} else if (is.list(ath)) {
athlete_id <- vapply(ath, function(a) {
as.character(if (is.list(a) || is.data.frame(a)) a[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
athlete_name <- vapply(ath, function(a) {
as.character(if (is.list(a) || is.data.frame(a)) a[["displayName"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
team_id <- NA_character_
if ("team" %in% colnames(items)) {
tm <- items[["team"]]
if (is.data.frame(tm)) {
team_id <- as.character(tm[["id"]] %||% NA_character_)
} else if (is.list(tm)) {
team_id <- vapply(tm, function(t) {
as.character(if (is.list(t) || is.data.frame(t)) t[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
from_team_id <- NA_character_
if ("fromTeam" %in% colnames(items)) {
ftm <- items[["fromTeam"]]
if (is.data.frame(ftm)) {
from_team_id <- as.character(ftm[["id"]] %||% NA_character_)
} else if (is.list(ftm)) {
from_team_id <- vapply(ftm, function(t) {
as.character(if (is.list(t) || is.data.frame(t)) t[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
to_team_id <- NA_character_
if ("toTeam" %in% colnames(items)) {
ttm <- items[["toTeam"]]
if (is.data.frame(ttm)) {
to_team_id <- as.character(ttm[["id"]] %||% NA_character_)
} else if (is.list(ttm)) {
to_team_id <- vapply(ttm, function(t) {
as.character(if (is.list(t) || is.data.frame(t)) t[["id"]] %||% NA_character_ else NA_character_)
}, character(1))
}
}
get_col <- function(df, col) {
if (col %in% colnames(df)) as.character(df[[col]]) else rep(NA_character_, nrow(df))
}
tx_df <- data.frame(
transaction_id = get_col(items, "id"),
date = get_col(items, "date"),
type = get_col(items, "type"),
description = get_col(items, "description"),
team_id = team_id,
athlete_id = athlete_id,
athlete_name = athlete_name,
from_team_id = from_team_id,
to_team_id = to_team_id,
stringsAsFactors = FALSE
) %>%
dplyr::as_tibble() %>%
make_wehoop_data("ESPN WNBA Transactions from ESPN.com", Sys.time())
},
error = function(e) .report_api_error(
e,
hint = "Failed to retrieve ESPN WNBA transactions for season {season}",
args = .args
),
warning = function(w) .report_api_warning(
w,
hint = "Warning retrieving ESPN WNBA transactions for season {season}",
args = .args
),
finally = {}
)
return(tx_df)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.